Matt RaibleMatt Raible is a Web Architecture Consultant specializing in open source frameworks.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

Agile Hiring Book Review

Agile Hiring While working for Time Warner Cable last year, I experienced a unique challenge: building a team of strong developers in a short amount of time. With the help of colleagues and my network, we were able to hire a team of 10 in 2 months. The reason for our success was largely because we experienced a number of strong applicants and we didn't have to reach beyond a couple Twitter posts to find anyone. I realize we were lucky in our pursuits to find strong people. We didn't have much of an interview process and we relied on friends' recommendations moreso than interviewing and evaluating candidates.

My contract ended with TWC in December. I could've converted to a full-time employee, but my boss recommended against it since it would've been a 50% salary reduction and lots of TWC politics if I moved into management. So I moved onto a great opportunity I had at Overstock.com. I started talking with Overstock shortly before I left for Devoxx and scheduled an interview in mid-December. My interview at Overstock was incredibly enjoyable and I quickly agreed to work for them.

A couple weeks ago, I received a copy of Agile Hiring from Sean Landis, one of the architects at Overstock. Sean was part of the team that interviewed me and joined a few of us for the 2nd part of my interview, a beautiful day of skiing at Snowbird. As I flipped through the pages of Agile Hiring, I realized they might've used some techniques on me, hence the reason I liked the interview so much and agreed to work there.

One of the things I liked best about Agile Hiring is that it emphasizes one of the guiding principles of Agile Development: people over process. It recommends you adjust your interview tactics for each candidate, rather than using a boilerplate approach for all candidates. It stresses the importance of a Tracking System (Overstock uses JIRA) to record notes during the process and notify those involved. One thing that became readily apparent as I read this book: if you want to interview right (and hire strong people), it's going to take a lot of time investment from your company. I don't think this is a bad thing, but it seems like a lot of companies viewing hiring as a nuisance, not an essential part of their business.

I chuckled a bit when I read that Sean recommended not hiring contractors (I am a contractor at Overstock), but loved his honesty when talking about the Google Effect during phone interviews. He also mentions a bunch of real-world issues with candidates, such as the Dunning-Kruger effect or getting candidates to admit they don't know something they've listed on their resumes. Also, he has great advice for getting straight answers from candidates when they keep skirting around the question. He emphasizes ending the interview process as soon as possible when the candidate doesn't fit in order to reduce costs and time investment. This is another agile recommendation: fail fast.

Section 3 on Reviewing Resumes has excruciating detail on what you should look for and how you should perform reviews. It also explains how many resumes will have truth stretching, but shouldn't have outright dishonesty. I think it's great how Sean recognizes the skills section of a resume will typically be stuffed with a list of buzzwords that add very little value. He says "the skills section is written with the purpose of getting the resume through filtering software." He also recognizes that those with certifications don't always have the most knowledge: "Unless you have good reason to act otherwise, treat certifications with skepticism."

The Phone Interview and On-Site Interview sections are great as they emphasize the importance of being a respectful interviewer and doing your best to sell your company. My favorite line is on page 176 when Sean talks about giving candidates a quick tour of your facility.

If you feel embarrassed to give candidates tours, put down this book and figure out why. Some salespeople can sell anything, but the best salespeople are selling products they believe in.

You can tell that folks at Overstock are proud of what they've built, especially when they post recruitment videos like their recent Looking for Java Developers.

The last chapter on Closing the Deal gives some unique insights to the interviewee on how companies might negotiate. Sean recommends giving fair offers, never lowballing and refusing to negotiate on salary (instead using one-time costs like signing bonuses and relocation packages to sweeten the deal).

I think Sean does a great job in showing how you can apply agile principles (people over process, tracking tools, failing fast, continuous improvement, constant feedback) to improve your hiring process. As a person that interviews often, I think it also gives great insights into how companies interview and what they're looking for. I've often thought that being honest about my skills and what I'm looking for is a good tactic and this book seems to confirm that. One things for sure, if I'm ever in the position to hire folks again, I'll have Agile Hiring by my side.

One of the things this book doesn't cover is how to source candidates or advertise positions. If you're looking for advice on that, I think A Vision for the Future of Recruitment: Recruitment 3.0 is a good start. This article has good advice, especially in that it points out the best candidates aren't looking for jobs. Posting on job boards, CV searching, etc. are only going to find candidates that are searching, and it's probably not the best talent pool.

Posted in Java at Jun 30 2011, 08:58:57 AM MDT 1 Comment

A Sweet Trip to Switzerland for Jazoon 2011

I've always enjoyed speaking at conferences, especially those in exotic locations. Earlier this year, I saw Jazoon's call for papers and thought, "I've never been to Switzerland, sounds fun!" I proceeded to submit a talk, got accepted and booked a trip with my girlfriend, Trish. We left Denver last Tuesday and arrived in Zürich on Wednesday around noon. After settling into our awesome accommodations at Hotel Opera, we journeyed to the conference location, which was held at a movie theater.

We were quickly impressed when we learned the conference had reserved a theater for an evening showing of The Hangover 2. We grabbed some drinks from the bar and settled in for a couple hours of giggling and barely staying awake from jetlag.

Zürich quickly made an impression on us the first day. We experienced its excellent transportation system (trains, trams, buses and boats) and saw a number of fancy cars (a Bently, a Lamborghini and a Ferrari). Prices were high, but the food was excellent.

Zürich Airport Sunset in Zürich Zurich Shopping District Ferrari Ferrari

On Thursday, we woke up and Trish realized she'd left her expensive Nikon lenses on our flight from Atlanta to Amsterdam. This realization hit her hard and she scrambled to try and find them by contacting the airlines. I rushed off to the conference to catch Frank Kim's What Every Developer Should Know About Application Security. This was a great session and I especially enjoyed that he selected Apache Roller as the application to hack. After that, I attended Ed Burns' Hyperproductive JSF and published my notes.

Then I met Trish for lunch at the conference and we went to the room for my talk. We had some technical difficulties to start (my brand-new Mini-DVI connector was bad) and I started about 10 minutes late. During this mad scramble to fix things, I started having some stomach issues, but ignored them thinking I could make it through my 50 minute talk. As I was doing demos and sweating profusely, I realized I couldn't make it and ran out of the room with 10 minutes left. The whole experience shook me up a bit. It was definitely not my best performance, but it could've been a lot worse. ;-)

Friday, we tried to sleep off our jet lag and woke up in the early afternoon. Trish had three places she wanted to visit and we managed to see them all in the same day. We climbed the tower at Grossmünster, rode the train to Rhine Falls and celebrated our anniversary at Gruelich, the highest-rated restaurant on TripAdvisor. We arrived at Guelich around 10pm and were very happy when they agreed to serve us. We did the 4-course meal and had the Sommelier choose our wines. It wasn't cheap, but definitely worth the experience.

View from Great Church Happy Couple in Zürich Riding the Train Rhine Falls!

Whoa! Rhine Falls Flowers

Olives and Sprouts Scallops and Tomato Dessert at Greulich Greulich's Backyard Trees

After dinner, we took the 8 Tram back to our hotel. However, it somehow turned into the 9 and we ended up on the opposite side of the lake. This turned out to be a nice diversion as we had a nice walk around the lake with some nice swans and lights on the water.

Swans on Lake Zürich Cool Lights Night Colors of Lake Zürich

Mmmmm, breakfast! Saturday, we woke up early for a big day of travel to the Swiss Alps. We enjoyed a scrumptious breakfast at the hotel and headed for the central train station. My good friend, Fernand, recommended we visit Grindelwald, while one of Trish's best friends thought we'd love the quaintness of Gimmelwald. We gulped at the price (500 USD) of the train ticket to both locations, but were impressed that you could buy all the tickets we needed (including the bus and trolley ride) at one place. We both quickly forgot the cost as we passed through the beautiful town of Interlaken and arrived in Grindelwald. An hour later we were hiking through Gletscherschlucht (Glacier Gorge) and marveling at the craftsmanship of the trail.

Grindelwald! Grindelwald, Switzerland Grindelwald from Gletscherschlucht Cue Water Rushing Sound

After enjoying a beer on a patio with a view, we boarded the train for Gimmelwald. A transfer, bus ride and cable car ride later, we were standing in the picturesque town, marveling that it had a lower elevation than Denver and perplexed that everyone seemed to be American. We strolled around, took a number of cool photos and had a scrumptious dinner at the Pension Gimmelwald.

Gimmelwald Gimmelwald Flora Path in Gimmelwald The Swiss Alps

Purple in Gimmelwald Trish as Julie Andrews Yodeling Cheers from Gimmelwald!

On our train ride home, we missed our connection in Interlaken. This was no surprise as we regularly encountered very short layovers between trains. The Swiss are incredibly efficient and our brief stop in a store (that had a line at the cashier) was enough to miss the next train. The hour layover turned into a nice opportunity to stroll around town and snap a few last pictures. I especially like the sunset below, taken around 9:30 at night.

Interlaken Sunset

Trish and I both were super-impressed with Zürich, the friendliness of the Swiss and especially the Swiss Alps. Yes, it was definitely expensive, but everything was top notch and beautiful. There's a very good chance we'll visit again. Thanks to the Jazoon Organizers for having us and providing us the opportunity to explore their gorgeous country.

Posted in General at Jun 28 2011, 12:52:33 PM MDT 4 Comments

My Java Web Application Security Presentation from Jazoon 2011

Yesterday I delivered my Java Web Application Security talk at Jazoon. The presentation I gave was similar to the one I delivered at Utah JUG, but contains a few more slides about penetration testing and securing REST APIs. I also opted not to embed the screencasts in the presentation on SlideShare since you can click on the links to view them. Lastly, I included a great quote from Erlend Oftedal, who left a great comment on my last post.

"Security is a quality, and as all other quality, it is important that we build it into our apps while we are developing them, not patching it on afterwards like many people do."

If you'd like to download a PDF of this presentation, you can do it from Slideshare or from my presentations page.

Like most conferences in the last year, I brought the lovely Trish McGinity with me. As of today, it's been one year since I saw her switch from a Martini to a Guinness and thought "I need to talk to that girl!" It's been a heckuva a ride ever since and I'm sure the future will be just as much fun. To celebrate, we're going to explore Rhine Falls and have dinner at Greulich. Happy Anniversary Trish!

Posted in Java at Jun 24 2011, 06:25:55 AM MDT 1 Comment

Hyperproductive JSF 2.0 with Ed Burns at Jazoon

This morning, I attended Ed Burn's Talk on Hyperproductive JSF 2.0 at Jazoon. As you might know, I've been a critic of JSF for many years. However, it is one of the most used Java web frameworks, so I was hoping to learn how it's improved in the latest version. Below are my notes from Ed's presentation.

Ed's Plan for our Time Investment:

  1. Define a productive development environment
  2. JSF for greenfield and brownfield projects
  3. List the top 9 productivity killers with JSF projects and solutions

"I am always doing that which I cannot do, in order that I may learn how to do it." -- Pablo Picasso

Software is an executable representation of knowledge, a byproduct of learning how to solve a problem. Knowledge is something that changes as more information comes in. A productive environment makes it as easy as possible to learn how to solve a problem. Learning is an iterative process. Early iterations don't need to be optimal. Later iterations do ... and they need to be maintainable. First is the hardest. Fast iterations are they key. Spring Roo and Play are examples of frameworks that make the first iteration very fast.

You should use a tool to jumpstart JSF development: copy from an old project, use a Maven archetype or use your IDE. With greenfield development, you don't have to bother learning the byproduct of other people's learning. It's a great opportunity to pad your resume with the latest hot technologies. With brownfield development, it's vitally important to understand the existing solution and hidden assumptions. You're also much more constrained in your technology choices. If you want to change, you'll need to come up with a migration strategy, which can be difficult. JSF works well for both because it's not just a runtime framework, it's also a conceptual framework. You need to understand how your framework handles data conversion, validation, page flow, persistence integration, I18N, L10N, A11Y, Web standards and user friendliness.

Top 9 JSF Productivity Killers:

  1. Time wasting deployment step
  2. The perils of "there's more than one way to do it"
  3. Lengthy and painful developer on-boarding process
  4. Misused logging and misunderstood error messages
  5. Phantoms
  6. Under-utilized developer tools
  7. Premature optimization
  8. Difficulty in doing TDD
  9. Lack of an app framework

Time wasting deployment step
ZeroTurnaround solves this problem with JRebel, but there's other ways to do it. Some of the killers of flow state: 1) one large war file, 2) underutilizing dynamic language features, 3) complex server environment and 4) build process is redoing work unnecessarily. To stop the time wasting deployment step, the most important things you can do are as follows:

  • Configure your IDE correctly. In Eclipse, compile directly into WEB-INF/classes and use continuous compilation. With NetBeans, use GlassFish.
  • Don't do control-flow programming in XML.

Ed then showed a simple demo that showed how you can use Groovy to create a JSF UI Component. He also mentioned that Groovy can be used to author any JSF artifact. The benefit of this is you can simply edit and save a .groovy file without having to recompile or redeploy. Unfortunately, using Groovy didn't eliminate the XML syntax for pages or the XML for defining UI components.

The perils of "there's more than one way to do it"
JSF is very flexible, but flexibility is, more often than not, abused. There's a lack of convention for common things (e.g. master-detail, JSF concepts like converter, validator, etc.). The best way to fix this is to establish the norms for a project and stick with them. For example, Neil Griffin has a good blog entry for the different kind of managed beans you can create. Develop recommendations like Neil's and use them on all your projects.

Lengthy developer on-boarding process
Stick with standards when possible (at least have a common project description and build system across projects). Be committed to periodic cleanup cycles, including documenting for re-use. Pick one JSF component library and stick with it. Support for mixing and switching component libraries has improved with JSF 2, but it's still recommended you use only one.

Misused logging and misunderstood error messages
JSF is notorious for cryptic error messages and very long stack traces. It's still a problem, but the JSF Team is still working on improving them. Good tip: use the <ui:debug> tag. Its recordStateSize="true" attribute can be especially useful. If you're using PrimeFaces, add trace=true to request URLs.

Phantoms
Phantoms is when running code is not the same as the code you are modifying or wrong version of library gets picked up. You should have the capability to hit breakpoints anywhere in your entire software stack, including core Java sources. This is one of the most useful things about open source software. Solutions to phantoms: 1) put a timestamp on every redeploy and have the timestamp appear in the system log 2) write the running library stack to the system log (each library and version being used) and make it easy to compare one developer's runtime stack with another's 3) consider doing all work in tightly controlled VMs (checkout the VM at the beginning of the day, do your work, commit your changes and throw your VM away at the end of the day).

Under-utilizing developer tools
Make sure everyone has the fastest machines available and as much screen real estate as desired. Hardware is much cheaper than developer time. Another tip is to use Hudson as your butler. It's not just the team CI server. In other words, take advantage of automation wherever you can.

Premature Optimization
Keep in mind the trade-offs between readability and performance. When using frameworks such as JSF, don't try to outsmart the implementation. Rather, use the framework as intended and use open-source contributions to treat performance problems. Example, EL expressions got a lot faster between EE5 and EE6. If you spent time trying to optimize EL expressions, you might've been wasting your time.

Difficulty in doing TDD
Try to figure out why TDD is difficult in your company. For JSF, strongly consider JBoss's JSFUnit. Write your testcases to extend from Cactus ServletTestCase and leverage HtmlUnit (JSFUnit does this for you).

Lack of an app framework
Create common components: login panel, CRUD components, etc. If you don't have an app framework, build one over time.

Conclusion
This was an interesting talk by Ed. The dynamics of the room where a bit interesting. Jazoon is held in a movie theater, much like Devoxx. However, it appears there's a spotlight on the speaker that makes it very difficult to see the audience. I don't remember having this problem at Devoxx. Ed asked the audience quite a few questions, but it seemed he had a lot of difficulty in seeing if folks raised their hands. This made for some periods of awkward silence.

Personally, I was hoping to learn some new whizbang tips about JSF that I was not aware of. Unfortunately, I didn't learn anything new and wasn't that impressed with the Groovy demo.

I think Ed's tips about things outside of JSF were good, especially buying developers good hardware. I've seen many companies, including my current client, skimp on developer hardware and cause developer frustration because of it. I think it's great when companies provide developers top-of-the-line hardware and eliminate frustration over CPU and memory resources. LinkedIn and Time Warner Cable both provide their developers with Mac Pros and MacBook Pros as well as huge monitors. IMO, this is one of the best benefits you can provide your engineers.

Posted in Java at Jun 23 2011, 04:53:10 AM MDT 3 Comments

Java Web Application Security - Part V: Penetrating with Zed Attack Proxy

Web Application Security is an important part of developing applications. As developers, I think we often forget this, or simply ignore it. In my career, I've learned a lot about web application security. However, I only recently learned and became familiar with the rapidly growing "appsec" industry.

I found a disconnect between what appsec consultants were selling and what I was developing. It seemed like appsec consultants were selling me fear, mostly because I thought my apps were secure. So I set out on a mission to learn more about web application security and penetration testing to see if my apps really were secure. This article is part of that mission, as are the previous articles I've written in this series.

When I first decided I wanted to do a talk on Webapp Security, I knew it would be more interesting if I showed the audience how to hack and fix an application. That's why I wrote it into my original proposal:

Webapp Security: Develop. Penetrate. Protect. Relax.
In this session, you'll learn how to implement authentication in your Java web applications using Spring Security, Apache Shiro and good ol' Java EE Container Managed Authentication. You'll also learn how to secure your REST API with OAuth and lock it down with SSL.

After learning how to develop authentication, I'll introduce you to OWASP, the OWASP Top 10, its Testing Guide and its Code Review Guide. From there, I'll discuss using WebGoat to verify your app is secure and commercial tools like webapp firewalls and accelerators.

At the time, I hadn't done much webapp pentesting. You can tell this from the fact that I mentioned WebGoat as the pentesting tool. From WebGoat's Project page:

WebGoat is a deliberately insecure J2EE web application maintained by OWASP designed to teach web application security lessons. In each lesson, users must demonstrate their understanding of a security issue by exploiting a real vulnerability in the WebGoat application. For example, in one of the lessons the user must use SQL injection to steal fake credit card numbers. The application is a realistic teaching environment, providing users with hints and code to further explain the lesson.

What I really meant to say and use was Zed Attack Proxy, also known as OWASP ZAP. ZAP is a Java Desktop application that you setup as a proxy for your browser, then use to find vulnerabilities in your application. This article explains how you can use ZAP to pentest a web applications and fix its vulnerabilities.

The application I'll be using in this article is the Ajax Login application I've been using throughout this series. I think it's great that projects like Damn Vulnerable Web App and WebGoat exist, but I wanted to test one that I think is secure, rather than one I know is not secure. In this particular example, I'll be testing the Spring Security implementation, since that's the framework I most often use in my open source projects.

Zed Attack Proxy Tutorial

Download and Run the Application
To begin, download the application and expand it on your hard drive. This app is the completed version of the Ajax Login application referenced in Java Web Application Security - Part II: Spring Security Login Demo. You'll need Java 6 and Maven installed to run the app. Run it using mvn jetty:run and open http://localhost:8080 in your browser. You'll see it's a simple CRUD application for users and you need to login to do anything.

Install and Configure ZAP
The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. Download the latest version (I used 1.3.0) and install it on your system. After installing, launch the app and change the proxy port to 9000 (Tools > Options > Local Proxy). Next, configure your browser to proxy requests through port 9000 and allow localhost requests to be proxied. I used Firefox 4 (Preferences > Advanced > Network > Connection Settings). When finished, your proxy settings should look like the following screenshot:

Firefox Proxy Settings

Another option (instead of removing localhost) is to add an entry to your hosts file with your production domain name. This is what I've done for this demo.

127.0.0.1       demo.raibledesigns.com

I've also configured Apache to proxy requests to Jetty with the following mod_proxy settings in my httpd.conf:

<IfModule mod_proxy.c>
    ProxyRequests Off 
    ProxyPreserveHost Off 

    <VirtualHost *:80>
       ProxyPass  /  http://localhost:8080/
    </VirtualHost>

    <VirtualHost *:443>
        SSLEngine on
        SSLProxyEngine on
        SSLCertificateFile "/etc/apache2/ssl.key/server.crt"
        SSLCertificateKeyFile "/etc/apache2/ssl.key/server.key"

        ProxyPass  /  https://localhost:8443/
    </VirtualHost>
</IfModule>

Perform a Scan
Now you need to give ZAP some data to work with. Using Firefox, I navigated to http://demo.raibledesigns.com and browsed around a bit, listing users, added a new one and deleted an existing one. After doing this, I noticed a number of flags in the ZAP UI under Sites. I then right-clicked on each site (one for http and one for https) and selected Attack > Active Scan site. You should be able to do this from the "Active Scan" tab at the bottom of ZAP, but there's a bug when the URLs are the same. After doing this, I received a number of alerts, ranging from high (cross-site scripting) to low (password autocomplete). The screenshot below shows the various issues.

ZAP Alerts

Now let's take a look at how to fix them.

Fix Vulnerabilities
One of the things not mentioned by the scan, but #1 in Seven Security (Mis)Configurations in Java web.xml Files, is Custom Error Pages Not Configured. Custom error pages are configured in this app, but error.jsp contains the following code:

<% if (exception != null) { %>
    <% exception.printStackTrace(new java.io.PrintWriter(out)); %>
<% } else { %>
    Please check your log files for further information.
<% } %>

Stack traces can be really useful to an attacker, so it's important to start by removing the above code from src/main/webapp/error.jsp.

The rest of the issues have to do with XSS, autocomplete, and cookies. Let's start with the easy ones. Fixing autocomplete is easy enough; simply changed the HTML in login.jsp and userform.jsp to have autocomplete="off" as part of the <form> tag.

Then modify web.xml so http-only and secure cookies are used. While you're at it, add session-timeout and tracking-mode as recommended by the aforementioned web.xml misconfigurations article.

<session-config>
    <session-timeout>15</session-timeout>
    <cookie-config>
        <http-only>true</http-only>
        <secure>true</secure>
    </cookie-config>
    <tracking-mode>COOKIE</tracking-mode>
</session-config>

Next, modify Spring Security's Remember Me configuration so it uses secure cookies. To do this, add use-secure-cookies="true" to the <remember-me> element in security.xml.

<remember-me user-service-ref="userService" key="e37f4b31-0c45-11dd-bd0b-0800200c9a66"
             use-secure-cookie="true"/>

Unfortunately, Spring Security doesn't support HttpOnly cookies, but will in a future release.

The next issue to solve is disabling directory browsing. You can do this by copying Jetty's webdefault.xml (from the org.eclipse.jetty:jetty-webapp JAR) into src/test/resources and changing its "dirAllowed" <init-param> to false:

<servlet>
  <servlet-name>default</servlet-name>
  <servlet-class>org.mortbay.jetty.servlet.DefaultServlet</servlet-class>
  <init-param>
    <param-name>acceptRanges</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>dirAllowed</param-name>
    <param-value>false</param-value>
  </init-param>
  <init-param>

You'll also need to modify the plugin's configuration to point to this file by adding it to the <webAppConfig> section in pom.xml.

<configuration>
    <webAppConfig>
        <contextPath>/</contextPath>
        <defaultsDescriptor>src/test/resources/webdefault.xml</defaultsDescriptor>
    </webAppConfig>

Of course, if you're running in production you'll want to configure this in your server's settings rather than in your pom.xml file.

Next, I set out to fix secure page browser cache issues. I had the following settings in my SiteMesh decorator:

<meta http-equiv="Cache-Control" content="no-store"/>
<meta http-equiv="Pragma" content="no-cache"/>

However, according to ZAP, the first meta tag should have "no-cache" instead of "no-store", so I changed it to "no-cache".

After making all these changes, I created a new ZAP session and ran an active scan on both sites again. Below are the results:

Active Scan after Fixes

I believe the first issue (parameter tampering) is because I show the error page when a duplicate user exists. To fix this, I changed UserFormController so it catches a UserExistsException and sends the user back to the form.

try {
    userManager.saveUser(user);
} catch (UserExistsException uex) {
    result.addError(new ObjectError("user", uex.getMessage()));
    return "userform";
}

However, this still doesn't seem to cause the alert to go away. This is likely because I'm not filtering/escaping HTML when it's first submitted. I believe the best solution for this would be to use something like OWASP's ESAPI to filter parameter values. However, I was unable to find integration with Spring MVC's data binding, so I decided not to try and fix this vulnerability.

Finally, I tried to disable jsessionid in URLs using suggestions from Stack Overflow. The previous setting in web.xml (<tracking-mode>COOKIE</tracking-mode>) should do this, but it doesn't seem to work with Jetty 8. The other issues (secure page browser cache, HttpOnly cookies and secure cookies), I was unable to solve. The last two are issues caused by Spring Security as far as I can tell.

Summary
In this article, I've shown you how to pentest a web application using Firefox and OWASP's Zed Attack Proxy (ZAP). I found ZAP to be a nice tool for figuring out vulnerabilities, but it'd be nice if it had a "retest" feature to see if you fixed an issue for a particular URL. It does have a "resend" feature, but running it didn't seem to clear alerts after I'd fixed them.

The issues I wasn't able to solve seemed to be mostly related to frameworks (e.g. Spring Security and HttpOnly cookies) or servers (Jetty not using cookies for tracking). My suspicion is the Jetty issues are because it doesn't support Servlet 3 as well as it advertises. I believe this is fair; I am using a milestone release after all. I tried scanning http://demo.raibledesigns.com/ajax-login (which runs on Tomcat 7 at Contegix) and confirmed that no jsessionid exists.

Hopefully this article has helped you understand how to figure out security vulnerabilities in your web applications. I believe ZAP will continue to get more popular as developers become aware of it. If you feel ambitious and want to try and solve all of the issues in my Ajax Login application, feel free to fork it on GitHub.

If you're interested in talking more about Webapp Security, please leave a comment, meet me at Jazoon later this week or let's talk in July at Über Conf.

Posted in Java at Jun 21 2011, 07:45:41 AM MDT 4 Comments

Good Times on The Annual Father's Day Camping Trip

Four years ago, I started an annual tradition with my kids: The Father's Day Camping Trip. The last two, I've flown my Dad in and we've journeyed to the Great Sand Dunes National Park. This year, we decided to stay a little closer to home and head up to Lake Granby. Both my parents flew in again, the kids returned from a month in Florida, and Trish and I packed up her puppies for a wonderful weekend.

When we arrived, the weather wasn't great. We showed up an hour before sunset and had just enough time to setup our tents before the rain started. It proceeded to rain throughout the night, but our tent help up nicely and we never got wet.

Lake Grandby Sunset Kids on the Beach

Mom and Dad - Fishing Preparations Stillwater Campground Rocks!

On Saturday, we did some fishing, hiked along the East Shore Trail, rode our bikes, and had a great time relaxing and enjoying each other's company. It only rained for a bit in the afternoon, the rest of the time we sat back and enjoyed beautiful views.

Beautiful Colorado Abbie on the shores of Lake Grandby

Happy Jack Mama Moose and Babies in Rocky Mountain National Park

On Sunday, we drove back through Rocky Mountain National Park, saw a moose and her two calves and enjoyed a delicious lunch at The Stanley Hotel in Estes Park. I really enjoyed spending so much time with my family this weekend. The good news is we get to do it again when I meet them at The Cabin in Montana next week. In the meantime, Trish and I are off to Jazoon for a few days of fun in Switzerland.

If you'd like to see more pictures from our Father's Day Camping Adventure, please see my Father's Day at Lake Granby album on Flickr.

Posted in General at Jun 20 2011, 10:38:01 PM MDT Add a Comment

Java Web Application Security - Part IV: Programmatic Login APIs

Over the last month, I've posted a number of articles on implementing authentication with Java EE 6, Spring Security and Apache Shiro. One of the things I demonstrated in my live demos (at Utah's JUG Meetings) was programmatic authentication. I left this out of my screencasts and previous tutorials because I thought it'd fit better in a comparison article.

In this article, I'd like to show you how you can programmatically login to an application using the aforementioned security frameworks. To do this, I'll be using my ajax-login application that I wrote for Implementing Ajax Authentication using jQuery, Spring Security and HTTPS.

To begin, I implemented a LoginController as a Spring MVC Controller that returns JSON.

package org.appfuse.examples.webapp.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/api/login.json")
public class LoginController {

    @Autowired
    LoginService loginService;

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public LoginStatus getStatus() {
        return loginService.getStatus();
    }

    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public LoginStatus login(@RequestParam("j_username") String username,
                             @RequestParam("j_password") String password) {

        return loginService.login(username, password);
    }
}

This controller delegates its logic to a LoginService interface.

package org.appfuse.examples.webapp.security;

public interface LoginService {

  LoginStatus getStatus();

  LoginStatus login(String username, String password);
}

The Client
The client for this controller is the same as mentioned in my previous article, but I'll post it again for your convenience. I used jQuery and jQuery UI to implement a dialog that opens the login page on the same page rather than redirecting to the login page. The "#demo" locator refers to a button in the page.

var dialog = $('<div></div>');

$(document).ready(function() {
    $.get('/login?ajax=true', function(data) {
        dialog.html(data);
        dialog.dialog({
            autoOpen: false,
	       title: 'Authentication Required'
        });
    });

    $('#demo').click(function() {
      dialog.dialog('open');
      // prevent the default action, e.g., following a link
      return false;
    });
});

The login page then has the following JavaScript to add a click handler to the "login" button that submits the request securely to the LoginController.

var getHost = function() {
    var port = (window.location.port == "8080") ? ":8443" : "";
    return ((secure) ? 'https://' : 'http://') + window.location.hostname + port;
};

var loginFailed = function(data, status) {
    $(".error").remove();
    $('#username-label').before('
Login failed, please try again.
'); }; $("#login").live('click', function(e) { e.preventDefault(); $.ajax({url: getHost() + "${ctx}/api/login.json", type: "POST", beforeSend: function(xhr) { xhr.withCredentials = true; }, data: $("#loginForm").serialize(), success: function(data, status) { if (data.loggedIn) { // success dialog.dialog('close'); location.href = getHost() + '${ctx}/users'; } else { loginFailed(data); } }, error: loginFailed }); });

The biggest secret to making this all work (the HTTP -> HTTPS communication, which is considered cross-domain), is the window.name Transport and the jQuery plugin that implements it. To make this plugin work with Firefox 3.6, I had to implement a Filter that adds Access-Control headers.

public class OptionsHeadersFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;

        response.setHeader("Access-Control-Allow-Origin", "http://" + req.getServerName());
        response.setHeader("Access-Control-Allow-Methods", "GET,POST");
        response.setHeader("Access-Control-Max-Age", "360");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
    }

    public void destroy() {
    }
}

Java EE 6 LoginService
Java EE 6 has a few new methods in HttpServletRequest:

  • authenticate(response)
  • login(user, pass)
  • logout()

In this example, I'll use the new login(username, password) method. The hardest part about getting this working was finding the right Maven dependency. At first, I tried the one that seemed to make the most sense:

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-web-api</artifactId>
    <version>6.0</version>
</dependency>

Unfortunately, this resulted in a strange error that means the dependency has the interfaces, but not the implementation classes. I ended up using GlassFish's dependency instead (thanks to Stack Overflow for the tip).

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.servlet</artifactId>
    <version>3.0</version>
    <scope>provided</scope>
</dependency>

Since Servlet 3.0 doesn't appear to be in Maven Central, I had to add the GlassFish Repository to my pom.xml's <repositories> element.

<repository>
    <id>glassfish-repo</id>
    <url>http://download.java.net/maven/glassfish</url>
</repository>

After that, it was easy to implement the LoginService interface with a JavaEELoginService class:

package org.appfuse.examples.webapp.security;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

@Service("javaeeLoginService")
public class JavaEELoginService implements LoginService {
    private Log log = LogFactory.getLog(JavaEELoginService.class);

    @Autowired
    HttpServletRequest request;

    public LoginStatus getStatus() {
        if (request.getRemoteUser() != null) {
            return new LoginStatus(true, request.getRemoteUser());
        } else {
            return new LoginStatus(false, null);
        }
    }

    @Override
    public LoginStatus login(String username, String password) {
        try {
            if (request.getRemoteUser() == null) {
                request.login(username, password);
                log.debug("Login succeeded!");
            }
            return new LoginStatus(true, request.getRemoteUser());
        } catch (ServletException e) {
            e.printStackTrace();
            return new LoginStatus(false, null);
        }
    }
}

I tried to use this with "mvn jetty:run" (with version 8.0.0.M2 of the jetty-maven-plugin), but I got the following error:

javax.servlet.ServletException
        at org.eclipse.jetty.server.Request.login(Request.java:1927)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:178)
        at $Proxy52.login(Unknown Source)
        at org.appfuse.examples.webapp.security.JavaEELoginService.login(JavaEELoginService.java:30)

This lead me to believe that Servlet 3 is not quite implemented, so I tried it with Tomcat 7.0.8. To support SSL and container-managed authentication, I had to create a certificate keystore and uncomment the SSL Connector in $CATALINA_HOME/conf/server.xml. I also had to add an "admin" user with roles="ROLE_ADMIN" to $CATALINA_HOME/conf/tomcat-users.xml.

<user username="admin" password="admin" roles="ROLE_ADMIN"/>

With Tomcat 7, I was able to login successfully, proven by the following logging.

DEBUG - JavaEELoginService.login(31) | Login succeeded!

However, in the UI, I still got a "Login failed, please try again." message. Recalling that I had some issues with ports previous, I configured Apache to proxy the default http/https ports to 8080/8443 and tried again. This time it worked!

Spring Security LoginService
Spring Security offers a programmatic API and I was able to implement its LoginService as follows:

package org.appfuse.examples.webapp.security;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.appfuse.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

@Service("springLoginService")
public class SpringSecurityLoginService implements LoginService {
    private Log log = LogFactory.getLog(SpringSecurityLoginService.class);

    @Autowired(required = false)
    @Qualifier("authenticationManager")
    AuthenticationManager authenticationManager;

    public LoginStatus getStatus() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && !auth.getName().equals("anonymousUser") && auth.isAuthenticated()) {
            return new LoginStatus(true, auth.getName());
        } else {
            return new LoginStatus(false, null);
        }
    }

    public LoginStatus login(String username, String password) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        User details = new User(username);
        token.setDetails(details);

        try {
            Authentication auth = authenticationManager.authenticate(token);
            log.debug("Login succeeded!");
            SecurityContextHolder.getContext().setAuthentication(auth);
            return new LoginStatus(auth.isAuthenticated(), auth.getName());
        } catch (BadCredentialsException e) {
            return new LoginStatus(false, null);
        }
    }
}

I then modified the LoginService dependency in LoginController so this implementation would be used.

@Autowired
@Qualifier("springLoginService")
LoginService loginService;

Since Spring's API doesn't depend on Servlet 3, I tried it in Jetty using "mvn jetty:run". Of course, I modified my web.xml accordingly for Spring Security before doing so. Interestingly enough, I found that the my SpringSecurityLoginService seemed to work:

DEBUG - SpringSecurityLoginService.login(39) | Login succeeded!

But in the UI, the login failed with a "Login failed, please try again." message. Using the standard ports with Apache in front of Jetty solved this issue.

Apache Shiro LoginService
Apache Shiro is nice enough to offer a programmatic API as well. I was able to implement a ShiroLoginService as follows:

package org.appfuse.examples.webapp.security;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;

@Service("shiroLoginService")
public class ShiroLoginService implements LoginService {
    private Log log = LogFactory.getLog(ShiroLoginService.class);

    public LoginStatus getStatus() {
        Subject currentUser = SecurityUtils.getSubject();
        if (currentUser.isAuthenticated()) {
            return new LoginStatus(true, currentUser.getPrincipal().toString());
        } else {
            return new LoginStatus(false, null);
        }
    }

    public LoginStatus login(String username, String password) {
        if (!getStatus().isLoggedIn()) {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            Subject currentUser = SecurityUtils.getSubject();
            try {
                currentUser.login(token);
                log.debug("Login succeeded!");
                return new LoginStatus(currentUser.isAuthenticated(),
                        currentUser.getPrincipal().toString());
            } catch (AuthenticationException e) {
                return new LoginStatus(false, null);
            }

        } else {
            return getStatus();
        }
    }
}

Then I modified the LoginService dependency in LoginController so this implementation would be used.

@Autowired
@Qualifier("shiroLoginService")
LoginService loginService;

Next, I modified my web.xml for Apache Shiro and tried "mvn jetty:run". Again, the login appeared to succeed (based on log messages) on the server, but failed in the UI. When using http://localhost instead of http://localhost:8080, everything worked fine.

Summary
This article has shown you how you can programmatically login using Java EE 6, Spring Security and Apache Shiro. Before Java EE 6 (and Servlet 3), there was no API to programmatically login, so this is a welcome addition. The fact that my Ajax login example didn't work when ports differed is because of browsers' same origin policy, which specifies the ports have to be the same. Specifying no ports (the defaults), seems to be the loophole.

On a related note, I've discovered some interesting articles recently from the AppSec Blog.

The 2nd article has an interesting paragraph:

... there's Apache Shiro (FKA JSecurity and then later as Apache Ki), another secure framework for Java apps. Although it looks simpler to use and understand than ESAPI and covers most of the main security bases (authentication, authorization, session management and encryption), it doesn't help take care of important functions like input validation and output encoding. And Spring users have Spring Security (Acegi) a comprehensive, but heavyweight authorization and authentication framework.

So according to this blog, the security frameworks discussed here aren't the best.

The most comprehensive, up-to-date choice for Java developers is OWASP's ESAPI Enterprise Security API especially now that the 2.0 release has just come out.

I haven't heard of many organizations adopting ESAPI over Java EE 6, Spring Security or Apache Shiro, but maybe I'm wrong. Is ESAPI something that's being used out there by companies?

Posted in Java at Jun 06 2011, 09:44:09 PM MDT 4 Comments

Music, Mountain Biking and Memories in Moab

Moab is one of my favorite place on Earth. It has been ever since I first journeyed there in college for a float trip down the Green River. Last year, I mountain biked in Moab for the first time and had a great time at Desert Rocks. This year, I made the trek again, but this time with the lovely Trish McGinity. The story of our drive out there last Friday is one of my favorites.

I've been a longtime fan of nice car stereos. You know, the ones you hate when you roll up to a stop light and their bass shakes your car. I, probably like you, don't enjoy someone else's nice stereo - but I've often enjoyed having one in my own car. It's been quite a few years since I've had a bass-tastic system in my car, but I still have the music on my iPhone.

So Trish and I are driving down I-70 in her Xterra and one of my old bass songs comes on. I say, "We can skip this one, it only sounds good on stereos with bass". She looks at me, cracks a half-smile and says "Oh, you don't think I have bass?" She then proceeds to turn some nobs and press some buttons and seconds later my seat is vibrating and the mirrors are shaking. I was appalled, overjoyed and super-impressed all at the same time. Turns out she has a Rockford Fosgate system with a subwoofer under the drivers seat and it sounded awesome. A wicked fun roadtrip ensued.

Shortly after my oh-my-god-you're-so-awesome-woman moment, we stopped in Fruita for a mountain bike ride on Horsethief Bench. This was a beautiful ride along the Colorado River with tons of flowers along the way.

Fruita Horsethief Bench in Fruita Hike-a-bike at Fruita

The purpose of our trip was 1) camping and enjoying the outdoors in Moab and 2) listening to great music at Desert Rocks. Our good friend, "The Professor", had driven out to Moab earlier in the week. He scored us a great camp site and we promptly set up our tent when we arrived. We installed some tikki torches, rolled out a small living room rug and settled into our camping chairs for cold beers. That evening, we saw several good bands and danced into the wee hours of the morning.

The rest of the weekend was spent 4x4ing, mountain biking, dancing and hiking in Arches National Park. We enjoyed tons of great music, with our favorites being Scenic Byway, Great American Taxi, JGB feat. Melvin Seals, MarchFourth Marching Band and Hot Buttered Rum.

One of the best way to describe good memories is with pictures. When you have a professional photographer with you, it only makes sense to end this post with some of Trish's best photos.

La Sal Mountains from Desert Rocks Scenic Byway

Bar-B or Killer B? Three Gossips and Tower of Babel

For more pictures, checkout my Moab and Desert Rocks 2011 Set on Flickr.

Posted in General at Jun 03 2011, 10:15:25 AM MDT 3 Comments

Upgraded to Roller 5.0 and added a Like Button

Apache Roller 4 was released in December 2007. After 3.5 years, Roller 5 has landed!

The major new feature in Roller 5.0 is Media Blogging, a set of enhancements to Roller's file upload and management capabilities. Also included in 5.0 are simple multi-site support, OpenID and OAuth support for Roller's AtomPub interface. All major dependencies have been updated and Roller now uses Maven for build and dependency management. You can find a summary of Roller 5.0's new features on the Roller wiki.

I upgraded to Roller 5.0, RC4 back in March and experienced a few issues. This morning, I upgraded to the final release and everything appears to working nice and smooth. To celebrate, I added a Facebook Like Button to each entry. Adding it was pretty straightforward. Below is the code I added to my _day.vm template:

<span id="fb-root"></span>
<script src="//connect.facebook.net/en_US/all.js#appId=226411374036019&xfbml=1"></script>
<fb:like href="$url.entry($entry.anchor)" send="false" show_faces="false" font="verdana"></fb:like>

I tried removing the <script> tag and putting it in my wro4j configuration file, but this caused the Like button to disappear. I also experimented with adding Twitter and LinkedIn buttons, but decided not to add them since it was difficult to get them all to align and look good together. However, if you'd like to add either of them to your Roller blog, you can do so with the following code:

<a href="http://twitter.com/share" class="twitter-share-button" 
    data-url="$url.entry($entry.anchor)" data-count="horizontal" data-via="mraible">Tweet</a>
<script type="text/javascript" src="//platform.twitter.com/widgets.js"></script>

<script type="text/javascript" src="//platform.linkedin.com/in.js"></script>
<script type="in/share" data-url="$url.entry($entry.anchor)" data-counter="right"></script>

Kudos to Dave for all his hard work on Roller throughout the years.

Posted in Roller at Jun 02 2011, 02:21:58 PM MDT Add a Comment