Sunday, August 7, 2011

Using Spring Security with Clojure/Compojure/Noir: Preliminaries

I don't know how to use Spring Security with Clojure web apps, but I'd like to learn how. I've got some clues, and I'm going to try and track them down and see how far I can get.

The first obstacle to overcome is that there doesn't seem to be anything in clojars I can just grab. Fortunately leiningen prints out some detailed error messages, which I can use to manually install the jar files I need. First I'll grab the jar files from http://www.springsource.com/download/community. Just the 3.0.5 release is all I need. I unzip the file, which gives me a directory with a number of different jar files in it.

Next, I cheat by editing my project.clj file to ask for a jar that doesn't exist. The lein deps command chugs along for a while, and then spews out a huge error dump, but with a little digging I can find this message somewhere in the middle:

Unable to resolve artifact: Missing:
----------
1) org.springframework.security:spring-security-parent:jar:3.0.5.RELEASE

  Try downloading the file manually from the project website.

  Then, install it using the command: 
      mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-parent -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=/path/to/file

There's the magical incantation I need. I'll just cheat again by editing the suggested maven command so that it installs each of the jar files that I downloaded from springsource. I don't know yet which specific jar files I'll need, so I'll install them all.

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-acl -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-acl-3.0.5.RELEASE.jar

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-aspects -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-aspects-3.0.5.RELEASE.jar

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-cas-client -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-cas-client-3.0.5.RELEASE.jar

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-config -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-config-3.0.5.RELEASE.jar

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-core -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-core-3.0.5.RELEASE.jar

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-ldap -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-ldap-3.0.5.RELEASE.jar

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-openid -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-openid-3.0.5.RELEASE.jar

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-taglibs -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-taglibs-3.0.5.RELEASE.jar

mvn install:install-file -DgroupId=org.springframework.security -DartifactId=spring-security-web -Dversion=3.0.5.RELEASE -Dpackaging=jar -Dfile=./spring-security-web-3.0.5.RELEASE.jar

If I cd into the directory where I extracted the Spring Security jars, I can just cut and paste this code, and have each of the spring-security-* jars installed in my local .m2 directory, where leiningen can find them.

Now I go back and edit project.clj, and add the core spring-security jar to my dependencies:

(defproject mm2 "0.1.0-SNAPSHOT"
            :description "FIXME: write this!"
            :dependencies [[org.clojure/clojure "1.2.1"]
                           [noir "1.1.0"]
                           ;; ADD SPRING SECURITY HERE:
                           [org.springframework.security/spring-security-core
                            "3.0.5.RELEASE"]]
            :main mm2.server)

Run lein deps and ... yup, the jar file is in lib/. It worked! Now I just need to figure out what other jar files I need (if any) and how to hook them into my clojure project. But that's a project for later.

Setting up Emacs clojure mode

Picking up where we left off in Starting from Scratch, we're next going to set up Emacs to be able to use clojure-mode for editing code, and to compile and run our Clojure programs for us. If you're new to Emacs, don't worry, we'll be taking this one step at a time.

The plain Linux system we installed in the first post comes with Emacs version 23. Version 24 comes with an Emacs extension called package.el< that makes it easier to add new functionality to Emacs by downloading pre-built extensions from sites like Marmalade. Version 23 doesn't have this built in, so we'll have to add it by hand, which fortunately is not hard.

$ mkdir ~/.emacs.d
$ cd ~/.emacs.d
$ wget http://bit.ly/pkg-el23

This will pull down the package.el file and install it in your .emacs.d directory, which is the standard place to put extensions for Emacs. Having the file in the .emacs.d directory only makes it available to Emacs, though. To actually use it, we need to modify the .emacs startup file.
$ emacs ~/.emacs
There may be some code already in the .emacs file, but we can safely skip over it for now. Go to the end of the file and add the following text:

(add-to-list 'load-path "~/.emacs.d")(require 'package) ;; loads package.el so we can use it
(add-to-list 'package-archives  '("marmalade" . "http://marmalade-repo.org/packages"))(package-initialize)
Quit Emacs and then open it up again. You should see the same opening screen as usual, but if there's a typo in the code you added to .emacs, you may see an error message instead. If that happens, open up .emacs again and double-check your typing, particularly single quotes and the dot between "marmalade" and the URL---it's not a comma. (The keyboard shortcut for opening a file is C-x-f, which is shorthand for Control-x followed by Control-f.)

Once your .emacs file loads correctly, we can go on to the next step. We're going to use the Emacs command line, aka the "minibuffer," to actually install a couple of packages. To get to this command line, type M-x, which is shorthand for Meta-x. "Meta-x" means hold down the "meta" key (Alt key on Windows keyboards) while typing an "x". At the very bottom of your Emacs window, you should see the string "M-x" followed by a flashing cursor. Emacs is waiting for your command. (Note: if you mistype and need to get out of the minibuffer, type Ctrl-g.)

We're going to give it a couple of commands. Let's start by installing paredit, a package that will automatically balance our parentheses for us.
M-x package-installInstall package: paredit
Next, we'll install clojure mode, which uses paredit.

M-x package-installInstall package: clojure-mode
Now we'll go back and make one last edit to .emacs. Type the following at the end of the file:
(defun turn-on-paredit () (paredit-mode 1))(add-hook 'clojure-mode-hook 'turn-on-paredit)
This will automatically turn on paredit mode whenever we edit a .clj file. Paredit mode is something people either love or hate because it forces you to keep your parentheses, braces, and square brackets matched. That's good, because otherwise you can get subtle bugs due to parentheses not closing where you thought, but sometimes paredit won't let you delete a single parenthesis even though you just want to move it someplace else.

I'll tell you the paredit trick, though: cut and paste. You can cut and paste any of the parenthesis-like characters even if paredit won't let you backspace over them to delete them. Less convenient than a simple backspace, perhaps, but it's a small price to pay for the extra functionality and safety that paredit gives you, especially if you're new to LISPs and Clojure.

We've got one last command to type at the command prompt:
$ lein plugin install swank-clojure 1.3.2
This installs the code that allows Emacs to hook up to Clojure so that you can actually run a Clojure REPL inside Emacs. The command to start a Clojure REPL inside Emacs is M-x clojure-jack-in. The REPL takes a few minutes to come up -- no getting around that JVM startup time -- but after a little bit you should see the friendly user=> prompt.

And now you're good to go: you have a high-powered editing environment all hooked into the Clojure REPL, so you can edit code, and run it, and even edit it while you are running it. How cool is that?

Comments, criticisms, corrections and questions are all welcome. Feel free to copy any or all of this post to use and/or improve for your own blog.