Thursday, March 22, 2012

Simplest Authentication in Lift

Lift has been an interesting experience so far, particularly since I'm learning Scala at the same time. Lift comes with quite a few built-in mechanisms to handle various features, such as authentication, authorization and role-based access control.

A lot of the documentation utilizes these built-ins to good effect, but because the core mechanisms are complete skipped, you have no idea where to start if you have to roll your own authentication. A suggestion for Lift documentation: cover the basic introduction first, then show how Lift builds on that foundation.

I present here the simplest possible authentication scheme for Lift, inspired by this page on the liftweb wiki:

object isLoggedIn extends SessionVar[Boolean](false)

// in Boot.scala
LiftRules.loggedInTest = Full(() => isLoggedIn.get)

That last line only needs to return a boolean. If you wish to include this with Lift's white-listed menu system, you merely need to add this sort of test:

val auth = If(() => !Authentication.user.isEmpty,
              () => RedirectResponse("/index"))
val entries = 
    Menu(Loc("Login", "index" :: Nil, "Login", Hidden)) :: 
    Menu(Loc("Some Page", "some-page" :: Nil, "Some-Page", auth)) ::

Any request other than /index that is not authenticated, ie. isLoggedIn.get returns false, will redirect to /index for login.

One caveat: since the authenticated flag session-level data, you are vulnerable to CSRF attacks unless you utilize Lift's built-in CSRF protection, where input names are assigned GUIDs. This is the default, but since it is easy to circumvent this to support simple query forms and the like, it's worth mentioning.

Monday, March 12, 2012

Debugging Lift 2.4 with Eclipse

To continue my last post, launching a Lift program and debugging from Eclipse turns out to be straightforward.

The starting point was this stackoverlow thread which pointed out the existence of the RunJettyRun Eclipse plugin, which can launch a Jetty instance from within Eclipse configured for remote debugging. Here are the steps to get launching and debugging working seamlessly:

  1. Install RunJettyRun from within Eclipse the usual way, ie. menu Help > Install New Software, then copy-paste this link.
  2. Once installed, go to menu Run > Debug Configurations, and double-click Jetty Webapp. This will create a new configuration for this project.
  3. Click Apply to save this configuration, and you can now start debugging to your heart's content.

NOTE: running Jetty in SBT via ~container:start puts the web app in the root of the web server, ie. http://localhost:8080/, but this plugin defaults to http://localhost:8080/project_name. You can change this via the "Context" parameter in the debug configuration. This defaults to the project name, presumably so you can run/debug multiple web apps simultaneously.

Getting Started with Scala Web Development - Lift 2.4 and SBT 0.11.2

Anyone following this blog knows I do most of my development in C#, but I recently had an opportunity for a Java project, so I'm taking the Scala plunge with Lift. It's been a bit of a frustrating experience so far since all of the documentation on any Java web framework assumes prior experience with Java servlets or other Java web frameworks.

Just a note, I'm not intending to bash anything, but I will point out some serious flaws in the tools or documentation that I encountered which seriously soured me on these tools. This is not a reason to get defensive, but it's an opportunity to see how accessible these tools are to someone with little bias or background in this environment.

In this whole endeavour, it was most frustrating trying to find a coherent explanation of the directory structures used by various build tools, JSPs and WARs. I finally managed to find a good intro for Lift that didn't assume I already knew how files are organized, and that started me on the right path. I soon after found a concise review of servlet directory structures written for the minimalist web4j framework which filled in the rest.

Of the IDEs I tried, IntelliJ IDEA and Eclipse both support Maven Lift project templates out of the box. However, Maven is not itself a dependency that they resolve and install for you. Combined with the fact that Maven is no longer the recommended method of building Lift programs, I saw little choice but to give that up as a bad job [1]. There is no working SBT support within these IDEs that I could see. IDEA had an SBT plugin, but it never worked for me.

So I set about playing with the recommended Simple Build Tool (SBT), but of course, the version shipped with Lift 2.4 is way out of date (0.7.7 IIRC, while the latest is 0.11.2). As a result, the terminology has changed somewhat, as the article I linked above mentions. I saw no reason to learn something already outdated, so my first project was to update the lift_blank build to SBT 0.11.2. This started the 13 page journey through SBT's getting started guide, much of which you have to understand to grok lift_blank's trivial build.

Fortunately, SBT is pretty cool. It can automatically download and register dependencies using Apache Ivy, and launch your web programs in Jetty for testing purposes. However, the intro and the default setup could definitely use a little work (at least for Lift documentation). For instance, to even make SBT usable in Lift scenarios, you need the xsbt-web-plugin, which itself requires you to define a plugin.sbt file in the appropriate location. What plugins are and where exactly plugins.sbt should go is on page 11 of the SBT getting started guide, and the need for that web plugin was buried in another page somewhere I accidentally found via Google after much searching on "not found" errors for "seq(webSettings :_*)".

The Final Solution

I present here the final toolset and configuration I settled on, combined with the updated and simplified build script for lift_blank which enabled me to finally work with code in a semi-usable environment:

  1. Download Eclipse Helios, and install it as you prefer. Helios is one version behind, but it's needed for Scala-IDE.
  2. Install the Scala-IDE Eclipse plugin.
  3. Install Scala 2.9.1. I'm not convinced this step is necessary, but it's what I did.
  4. Download Lift 2.4.
  5. Unpack and go into lift-lift_24_sbt-f911f30\scala_29\lift_blank.
  6. Delete project\build directory, and sbt-launcher.jar, sbt, sbt.bat. The only remaining sbt-specific file is project\
  7. Open project\ in a text editor, and replace "sbt.version=0.7.7" with "sbt.version=0.11.2", "def.scala.version=2.7.7" with "def.scala.version=2.9.1".
  8. Download sbt-launch.jar from this page and place it in the lift_blank root directory.
  9. Create an sbt.bat in the lift_blank root directory file with the following contents:
    set SCRIPT_DIR=%~dp0
    java -Xmx512M -jar "%SCRIPT_DIR%sbt-launch.jar" %*
    This simply runs the sbt-launch.jar you just downloaded.
  10. Run sbt.bat. You will get an error, but this will create the ~/.sbt directory where global SBT settings are stored.
  11. Go to your root user directory, ie. in Windows 7, this is the start menu > [Your User Name]. You should see a .sbt folder there. Enter it and create a folder called "plugins".
  12. Under the above plugins folder, create a file called "plugins.sbt" with the following contents:
    addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0")
    libraryDependencies <+= sbtVersion(v => "com.github.siasia" %% "xsbt-web-plugin" % (v+"-0.2.11"))
    This simply adds Eclipse and web app support to SBT. You could also put this plugins folder under lift_blank\project, but I just made it a global setting so I never have to fiddle with it again.
  13. Return to folder lift_blank, and create a file called "build.sbt" with the following contents:
    name := "lift_blank"
    version := "1.0"
    scalaVersion := "2.9.1"
    seq(webSettings :_*)
    libraryDependencies ++= Seq(
        "net.liftweb" %% "lift-webkit" % "2.4" % "compile->default",
        "org.mortbay.jetty" % "jetty" % "6.1.26" % "container,test",
        "junit" % "junit" % "4.7" % "test",
        "ch.qos.logback" % "logback-classic" % "0.9.26",
        "org.scala-tools.testing" %% "specs" % "1.6.9" % "test")
    This is the simplified and updated build file for lift.
  14. Now execute sbt.bat and you should get an SBT command prompt. Type "compile" and watch SBT download all the dependencies listed above in build.sbt, and compile the source code.
  15. Now type "eclipse" at SBT's command prompt, and this will generate Eclipse project files.
  16. Launch Eclipse, and go to File > Import, select General > Existing Projects into Workspace, then click Next. Navigate to and select your lift_blank folder and click Finish.
  17. Go to menu Project > Properties, and select the Builders option on the left hand side.
  18. Click New, select Program, click OK. This will bring up an "Edit Configuration" dialog.
  19. In the "Name" field, type "SBT Builder".
  20. Under the "Location" section, click Browse Workspace, and select sbt.bat.
  21. Under the "Working Directory" section, click Browse Workspace, and select lift_blank, ie. your project name.
  22. Under the "Arguments" section, type in compile, and click OK.

You now have a working, update to date SBT build and a valid Eclipse project. Happy hacking!

You can start Jetty by executing sbt ~container:start.


There is no way it should be this convoluted to get a working build and a working IDE. This solution isn't even complete, as I'm still working on getting the tests to run and Jetty to launch, and I hold out little hope for debugging. It also seems like any change to the build, like adding a new dependency, requires regenerating the Eclipse files and restarting Eclipse. Any suggestions here would be much appreciated! An SBT plugin for Eclipse would be most welcome. :-)

Some suggestions for Lift documentation: a complete intro to directory structures would only cost a few paragraphs, and would make your project accessible even to beginners. A short review of the build tool would also be helpful.

Suggestions for SBT:

  1. Remove 90% of the documentation in the getting started guide. In particular, getting started generally doesn't involve recursive builds, contexts, key dependencies, scopes and how it all works at the Scala level, ie. immutable sequences, etc. I think the getting started guide should be focused on directory layout, settings, simple library dependencies, common commands, and batch/interactive mode, all using the simplified .sbt build file. This shouldn't take more than 2 pages, and anything else should be in an advanced guide.
  2. I'm still learning Scala, but I still stumble over libraryDependencies. I often get confused over exactly which column version numbers go in. It would help tremendously if there were some named parameter syntax that would make this obvious, ie. something like:
      package: "net.liftweb",
      jar: "lift-webkit",
      version: "2.4",
      into: "compile->default")

[1] As an aside, I'd just like to mention that IntelliJ was particularly annoying because I couldn't seem to open any file that wasn't already part of a project. Why can't I just open any old text file? Drag and drop certainly didn't work, and adding a folder to a project that already exists in the project directory also seemed impossible. I haven't used Eclipse as much yet, but I will no doubt find similar irritations. One instant irritation is the lack of installer for Windows, though I can appreciate how that might be a low priority for Eclipse devs.

Sunday, March 4, 2012

Oh C#, why must you make life so difficult?

Ran into a problem with C#'s implicit conversions, which don't seem to support generic types:

class Foo<T>
    public T Value { get; set; }
    public static implicit operator Foo<T>(T value)
        return new Foo<T> { Value = value };
static class Program
    static void Main(string[] args)
        // this is fine:
        Foo<IEnumerable<int>> x = new int[0];

        // this is not fine:
        Foo<IEnumerable<int>> y = Enumerable.Empty<int>();
        //Error 2: Cannot implicitly convert type 'IEnumerable<int>'
        //to 'Foo<IEnumerable<int>>'. An explicit conversion
        //exists (are you missing a cast?

So basically, you can't implicitly convert nested generic types, but implicit array conversions work just fine.