The server
**********

The claw application server is hold into the claw-as package. To load it you simply have to use asdf with the command

     (asdf:oos 'asdf:load-op :claw-as)

The application server is defined by the class CLAWSERVER.

A CLAWSERVER instance is able to start and stop services that are subclasses of the CLAW-SERVICE interface, dispatch HTTP and HTTPS request and log messages through CONNECTOR and  LOGGER implementations that are CLAW-SERVICE implementations.

A minimal server configuration needs an connector, a SESSION-MANAGER (another CLAW-SERVICE that handles user sessions) and a log manager to logs server messages.

Currently claw application server uses a connector to Hunchentoot (see: unchentoot (http://www.weitz.de/hunchentoot/)), a wonderful as powerful web server written in Common Lisp.

The log manager HUNCHENTOOT-LOGGER is also based on Hunchentoot logging system.

The connector,as an Hunchentoot wrapper CLAWSERVER ``provides facilities like automatic session handling (with and without cookies), logging (to Apache's log files or to a file in the file system), customizable error handling, and easy access to GET and POST parameters sent by the client.''

Starting the application server
===============================

To stare the server you have to pass it a http connector that may be instantiated with

     (defvar *ht-connector* (make-instance 'hunchentoot-connector
                                           :address "localhost"
                                           :port 4242
                                           :sslport nil))

This makes the connector to listen on port 4242 for http requests.

Once created your connector you have to provide to the server a logger. Using HUNCHENTOOT-LOGGER service instantiated like

     (defvar *ht-log-manager* (make-instance 'hunchentoot-logger))

You then have to instantiate a session manager service that will handle user sessions.

     (defvar *sm* (make-instance 'default-session-manager))

Now you are ready to instantiate the application server.

     (defvar *demo-server* (make-instance 'claw-server
                                     :connector *ht-connector*
                                     :log-manager *ht-log-manager*
                                     :session-manager *sm*
                                     :base-path "/claw"
                                     :reverse-proxy-path "/claw"))

BASE-PATH is the path where all your web applications will go under when directly accessing claw application server, while REVERSE-PROXY-PATH is the path used when passing requests through Apache mod_proxy.

The application server is tow ready to be started.

     (claw-server-start *demo-server*)

Test now with your browser the url http://localhost:4242/claw

You can see a page reporting a 404 error, this is normal since we haven't already provided any LISPLET or resource to the server.

you can stop the server with

     (claw-server-stop *demo-server*)

Lisplets
========

claw has the notion of lisplets, components similar to java servlets, but written in Common Lisp.

As the name suggests, a lisplet is defined by the LISPLET class. A lisplet is an envelop for your application, so claw-server, being an application server, may hold more than one web application, each sharing or protecting its realm with other web applications. This means that an application may or may not share user sessions among the others, configuring its own realm.

A lisplet contains all the resources (dynamic pages, static files, and services) that your application may need.

Registering a LISPLET into the application server is very easy,  in fact you only need to instantiate a LISPLET object with its proper realm defined, and tell the server to register it. The default realm for a lisplet is "claw", if not defined differently during its creation; when two or more lisplets share the same realm, they will share user sessions too.

     (defvar *sample-lisplet*
       (make-instance 'lisplet :realm "demo"
                      :base-path "/demo"))

When defining the lisplet BASE-PATH options claw application server will build a path to that requests that come, will have to match the application server path plus the lisplet one.

Let's now add an index page. We will not use any web framework yet, just plain text.

     (lisplet-register-function-location
       *sample-lisplet*
       #'(lambda () "<html>
                             <head>
                                     <title>A very simple page</title>
                             <head>
                             <body>
                                     <h1>hello world!</h1>
                             </body>
                     </html>")
       "index.html"
       :welcome-page-p t)

When setting the WELCOME-PAGE-P to T, it means that it will be your application welcome page, as the name suggests. Of course there may be only one welcome page per application. So, in the sample above, you can access the page browsing http://localhost:4242/claw/demo/index.html, but also http://localhost:4242/claw/demo and http://localhost:4242/claw/demo/.

We haven't defined a mime type, because claw application server is able to recognise it by uri extension.

When an uri extension is not recognised, you have to tell the server what's the resource mime-type. So we will slightly change the example above to test it.

     (lisplet-register-function-location
       *sample-lisplet*
       #'(lambda () "<html>
                             <head>
                                     <title>A very simple page</title>
                             <head>
                             <body>
                                     <h1><a href='info.do'>hello world!</a></h1>
                             </body>
                     </html>")
       "index.html"
       :welcome-page-p t)

     (lisplet-register-function-location
       *sample-lisplet*
       #'(lambda ()
                 (setf (claw-content-type) "text/html")
                 "<html>
                     <head>
                             <title>A very simple info</title>
                     <head>
                     <body>
                             <h2>It's running!</h2>
                     </body>
                  </html>")
       "info.do")

Finally you have to register the lisplet into the application server.

     (claw-server-register-lisplet *demo-server* *sample-lisplet*)

Now you are ready to put all together and try on your own your first claw application.

     ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
     ;;; $Header: claw-demo1.lisp $
     (in-package :cl-user)

     (eval-when (:compile-toplevel :load-toplevel)
       (asdf:oos 'asdf:load-op :claw-as)
       (asdf:oos 'asdf:load-op :claw-hunchentoot-connector))

     (defpackage :claw-demo1
       (:use :cl :claw-as :claw-hunchentoot-connector))

     (in-package :claw-demo1)

     (defvar *ht-connector* (make-instance 'hunchentoot-connector
                                           :address "localhost"
                                           :port 4242
                                           :sslport nil))

     (defvar *ht-log-manager* (make-instance 'hunchentoot-logger))

     (defvar *sm* (make-instance 'default-session-manager))

     (defvar *demo-server* (make-instance 'claw-server
                                     :connector *ht-connector*
                                     :log-manager *ht-log-manager*
                                     :session-manager *sm*
                                     :base-path "/claw"
                                     :reverse-proxy-path "/claw"))

     (defvar *sample-lisplet*
       (make-instance 'lisplet :realm "demo"
                      :base-path "/demo"))

     (lisplet-register-function-location
       *sample-lisplet*
       #'(lambda () "<html>
                             <head>
                                     <title>A very simple page</title>
                             <head>
                             <body>
                                     <h1><a href='info.do'>hello world!</a></h1>
                             </body>
                     </html>")
       "index.html"
       :welcome-page-p t)

     (lisplet-register-function-location
       *sample-lisplet*
       #'(lambda ()
                 (setf (claw-content-type) "text/html")
                 "<html>
                     <head>
                             <title>A very simple info</title>
                     <head>
                     <body>
                             <h2>It's running!</h2>
                     </body>
                  </html>")
       "info.do")

     (claw-server-register-lisplet *demo-server* *sample-lisplet*)

     (claw-server-start *demo-server*)

You now can brows your new mini application opening your browser at http://localhost:4242/claw/demo/.

External resources
==================

When you want to make accessible you local file-system claw application server provides an easy way to register them into your application.

For example in a Unix operating system you can access /tmp resources using the LISPLET-REGISTER-RESOURCE-LOCATION method. So you can add to the example of the previous chapter the following code:

     (lisplet-register-resource-location *sample-lisplet*
                                         #P"/tmp/"
                                         "docroot/")

Now you can see the server log file pointing you browser to the following url http://localhost:4242/claw/demo/docroot/hunchentoot.log.

Note that you can add and remove resources to a running lisplet, which speeds up project development and is particularly suited to dynamic sites like a CMS (http://en.wikipedia.org/wiki/Content_management_system).

You could also register the single ``/tmp/hunchentoot.log'' file into your lisplet, this would protect other resources making them inaccessible by the users of you application.

There are cases where you may need to stream resources that are not in the file system, for example when you have to generate pdf invoices or dynamic generated images.

This again is another easy task, simply use LISPLET-REGISTER-FUNCTION-LOCATION as you did for the two pages in the example of the previous chapter.

To see an example of this, download a jpg image and put it under the /tmp directory, naming it 'foo.jpg'. Then use the following code to register it into your servlet.

     (lisplet-register-function-location
      *sample-lisplet*
      (lambda ()
        (setf (claw-content-type) "image/jpeg")
        (with-open-file (in #P"/tmp/foo.jpg" :element-type '(unsigned-byte 8))
          (let ((image-data (make-array (file-length in)
                                        :element-type '(unsigned-byte 8))))
            (read-sequence image-data in)
            image-data)))
      "images/foo.bar" )

Now you can access your ``generated'' image by pointing your browser at the url http://localhost:4242/claw/demo/images/foo.bar. Though you have called the image ``foo.bar'', since you have provided the resource registration setting its content type with ``image/jpeg'', it is rendered as a normal jpeg image even if its extension is ``.bar''.

System wide resources
=====================

One of the other great feature of claw are system wide resources.

When you define a system wide resource, this will be available to all your registered lisplets. This feature gives you the possibility to create claw libraries whose resources are available to all your lisplets. An example of a claw library is the claw-html.dojo library that extends the claw-html web framework and provides all the dojo (http://www.dojotoolkit.org) resources to the server web applications.

Defining a system wide resource is not so different to a local one: the following code gives you an example on how to do.

     (register-library-resource "tempdir/" #P"/tmp/")

One difference from a local and a system wide resource is that REGISTER-LIBRARY-RESOURCE registers the resource at the application server level and not at the lisplet level.

This means that the resource in the example is available at the following url http://localhost:4242/claw/tempdir/hunchentoot.log.

Authentication and authorization
================================

Sometimes you may have the need to protect particular resources because they might contain sensible data, or any other reason.

claw application server provides such functionalities.

Firstly you need to instantiate a subclass of CONFIGURATION class and successively register into claw application server. You also need to implement the CONFIGURATION-LOGIN method that will perform the authentication logic.

claw may handle both basic an form based authentication types, you'll begin to see a basic authentication and then will change it into a form based one.

Now begin defining a CONFIGURATION subclass implementing its CONFIGURATION-LOGIN method and add it to your previous sample.

     (defclass demo-configuration (configuration)
       ((users :reader users
               :initform '(("admin" "pwdadmin" ("admin-role" "user-role"))
                           ("user1" "pwduser" ("user-role"))))))

     (defmethod configuration-login ((configuration demo-configuration))
       (multiple-value-bind (user password)
             (if (eq (lisplet-authentication-type *claw-current-lisplet*) :basic)
                 (claw-authorization)
                 (values (claw-parameter "username")
                         (claw-parameter "password")))
           (let ((maybe-principal (assoc user)))
             (when (and maybe-principal (string= password (second maybe-principal)))
               (make-instance 'principal
                              :name user
                              :roles (third maybe-principal))))))

As for any other resource you have to register the CONFIGURATION, but not into your lisplet, instead the CONFIGURATION must be registered with the claw application server; because it is cross-application, that means that more than one lisplet may share the same authentication configuration.

     (claw-server-register-configuration *demo-server* "demo" (make-instance 'demo-configuration))

For your example, the *SAMPLE-LISPLET* lisplet instance has been registered into the "demo" realm. This means that authentication is performed for a configuration that matches the same realm. For this reason the code above sets the second parameter of the claw-server-REGISTER-CONFIGURATION to "demo".

The *claw-current-lisplet* is a locally scoped variable that the application server sets while it's performing the request dispatching.

The LISPLET-AUTHENTICATION-TYPE method returns :BASIC when the authentication type is basic, while it returns :FORM when it is form based.

When the authentication type is basic the CLAW-AUTHORIZATION function returns a value pair, containing the passed user name and password, whereas, when the authentication type is form based, user name and password are retrieved from the http request.

To get a parameter from the http request claw provides three methods.

  - claw-get-parameter To get parameters when performing a get method.

  - claw-post-parameter To get parameters when performing a post method.

  - claw-parameter Returns the value of the GET or POST parameter, when no GET one is found.

Now you only need to protect some resource into your lisplet, so you'll now add a new one into your sample and protect it with the newly defined configuration.

Firstly you'll try the basic authentication mode, then the form based one.

     (lisplet-register-function-location
       *sample-lisplet*
       #'(lambda () (format nil
                            "<html>
                               <head>
                                 <title>protected resource</title>
                               <head>
                               <body>
                                 <h2>Welcome ~a</h2>
                                 ~@[~a~]
                               </body>
                             </html>"
                             (principal-name (current-principal))
                             (when (user-in-role-p '("admin-role"))
                                   "<h3>You are an administrator now!</h3>")))
       "protected.html")

     (lisplet-protect *sample-lisplet* "protected.html" '("admin-role" "user-role"))

Here it is the full code:

     (in-package :cl-user)

     (eval-when (:compile-toplevel :load-toplevel)
       (asdf:oos 'asdf:load-op :claw-as)
       (asdf:oos 'asdf:load-op :claw-hunchentoot-connector))

     (defpackage :claw-demo1
       (:use :cl :claw-as :claw-hunchentoot-connector))

     (in-package :claw-demo1)

     (defvar *ht-connector* (make-instance 'hunchentoot-connector
                                           :address "localhost"
                                           :port 4242
                                           :sslport nil))

     (defvar *ht-log-manager* (make-instance 'hunchentoot-logger))

     (defvar *sm* (make-instance 'default-session-manager))

     (defvar *demo-server* (make-instance 'claw-server
                                          :connector *ht-connector*
                                          :log-manager *ht-log-manager*
                                          :session-manager *sm*
                                          :base-path "/claw"
                                          :reverse-proxy-path "/claw"))

     (defvar *sample-lisplet*
       (make-instance 'lisplet :realm "demo"
                      :base-path "/demo"))

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda () "<html>
                             <head>
                                     <title>A very simple page</title>
                             <head>
                             <body>
                                     <h1><a href='info.do'>hello world!</a></h1>
                                     <h1><a href='protected.html'>protected!</a></h1>
                             </body>
                     </html>")
      "index.html"
      :welcome-page-p t)

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda ()
          (setf (claw-content-type) "text/html")
          "<html>
                     <head>
                             <title>A very simple info</title>
                     <head>
                     <body>
                             <h2>It's running!</h2>
                     </body>
                  </html>")
      "info.do")

     (claw-server-register-lisplet *demo-server* *sample-lisplet*)

     (claw-server-start *demo-server*)

     (lisplet-register-resource-location *sample-lisplet*
                                         #P"/tmp/"
                                         "docroot/")

     (lisplet-register-function-location
      *sample-lisplet*
      (lambda ()
        (setf (claw-content-type) "image/jpeg")
        (with-open-file (in #P"/tmp/foo.jpg" :element-type '(unsigned-byte 8))
          (let ((image-data (make-array (file-length in)
                                        :element-type '(unsigned-byte 8))))
            (read-sequence image-data in)
            image-data)))
      "images/foo.bar" )

     (register-library-resource "tempdir/" #P"/tmp/")

     (defclass demo-configuration (configuration)
       ((users :reader users
               :initform '(("admin" "pwdadmin" ("admin-role" "user-role"))
                           ("user1" "pwduser" ("user-role"))))))

     (defmethod configuration-login ((configuration demo-configuration))
       (multiple-value-bind (user password)
           (if (eq (lisplet-authentication-type *claw-current-lisplet*) :basic)
               (claw-authorization)
               (values (claw-parameter "username")
                       (claw-parameter "password")))
         (let ((maybe-principal (assoc user (users configuration) :test #'equal)))
           (when (and maybe-principal (string= password (second maybe-principal)))
             (setf (current-principal) (make-instance 'principal
                                                      :name user
                                                      :roles (third maybe-principal)))))))

     (claw-server-register-configuration *demo-server* "demo" (make-instance 'demo-configuration))

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda () (format nil
                           "<html>
                               <head>
                                 <title>protected resource</title>
                               <head>
                               <body>
                                 <h2>Welcome ~a</h2>
                                 ~@[~a~]
                               </body>
                             </html>"
                           (principal-name (current-principal))
                           (when (user-in-role-p '("admin-role"))
                             "<h3>You are an administrator now!</h3>")))
      "protected.html")

     (lisplet-protect *sample-lisplet* "protected.html" '("admin-role" "user-role"))

Please note, with respect to (setf (current-principal) ...) that stores the newly created principal into the lisplet session.

The method LISPLET-PROTECT protects a given resource, identified by its lisplet-relative uri, against a list of given roles. In the current example the page ``protected.html'' will be available only to users that belong to the ``admin-role'' and ``user-role''.

The function USER-IN-ROLE-P checks if the principal returned by the function CURRENT-PRINCIPAL, belongs to at least one of the given roles. This method is useful for conditionally including content,as we did above.

Now it's time to move the demo lisplet to form based authentication.

The form based authentication method is not much more difficult from the basic one, you just have to crate a form that calls the CONFIGURATION-LOGIN of the configuration retrieved by the CURRENT-CONFIGURATION function.

You then have to register the page containing such form as a login page.

The following example clarify what just described

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda ()
          (configuration-login (current-config))
          (if (current-principal)
              (claw-redirect "protected.html")
              "<html>
                 <head>
                   <title>A very simple page</title>
                 <head>
                 <body>
                   <h1>User login</h1>
                   <form method='post'>
                     username <input type='text' name='username'>
                     password <input type='password' name='password'>
                     <input type='submit' name='submit' value='Login'>
                   </form>
                 </body>
               </html>"))
      "login.html"
      :login-page-p t)

This is not much more than the effort for using the basic authentication method.

You have only to notice that the name tag attribute of the input boxes for username and password must match the parameters expected into the CONFIGURATION-LOGIN method implementation. For this example they are in fact ``username'' and ``password''.

The logout phase is even more simple, you only need to destroy the user session calling the function claw-remove-session.

So putting it all together

     (in-package :cl-user)

     (eval-when (:compile-toplevel :load-toplevel)
       (asdf:oos 'asdf:load-op :claw-as)
       (asdf:oos 'asdf:load-op :claw-hunchentoot-connector))

     (defpackage :claw-demo1
       (:use :cl :claw-as :claw-hunchentoot-connector))

     (in-package :claw-demo1)

     (defvar *ht-connector* (make-instance 'hunchentoot-connector
                                           :address "localhost"
                                           :port 4242
                                           :sslport nil))

     (defvar *ht-log-manager* (make-instance 'hunchentoot-logger))

     (defvar *sm* (make-instance 'default-session-manager))

     (defvar *demo-server* (make-instance 'claw-server
                                          :connector *ht-connector*
                                          :log-manager *ht-log-manager*
                                          :session-manager *sm*
                                          :base-path "/claw"
                                          :reverse-proxy-path "/claw"))

     (defvar *sample-lisplet*
       (make-instance 'lisplet :realm "demo"
                      :base-path "/demo"))

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda () "<html>
                             <head>
                                     <title>A very simple page</title>
                             <head>
                             <body>
                                     <h1><a href='info.do'>hello world!</a></h1>
                                     <h1><a href='protected.html'>protected!</a></h1>
                             </body>
                     </html>")
      "index.html"
      :welcome-page-p t)

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda ()
          (setf (claw-content-type) "text/html")
          "<html>
                     <head>
                             <title>A very simple info</title>
                     <head>
                     <body>
                             <h2>It's running!</h2>
                     </body>
                  </html>")
      "info.do")

     (claw-server-register-lisplet *demo-server* *sample-lisplet*)

     (claw-server-start *demo-server*)

     (lisplet-register-resource-location *sample-lisplet*
                                         #P"/tmp/"
                                         "docroot/")

     (lisplet-register-function-location
      *sample-lisplet*
      (lambda ()
        (setf (claw-content-type) "image/jpeg")
        (with-open-file (in #P"/tmp/foo.jpg" :element-type '(unsigned-byte 8))
          (let ((image-data (make-array (file-length in)
                                        :element-type '(unsigned-byte 8))))
            (read-sequence image-data in)
            image-data)))
      "images/foo.bar" )

     (register-library-resource "tempdir/" #P"/tmp/")

     (defclass demo-configuration (configuration)
       ((users :reader users
               :initform '(("admin" "pwdadmin" ("admin-role" "user-role"))
                           ("user1" "pwduser" ("user-role"))))))

     (defmethod configuration-login ((configuration demo-configuration))
       (multiple-value-bind (user password)
           (if (eq (lisplet-authentication-type *claw-current-lisplet*) :basic)
               (claw-authorization)
               (values (claw-parameter "username")
                       (claw-parameter "password")))
         (let ((maybe-principal (assoc user (users configuration) :test #'equal)))
           (when (and maybe-principal (string= password (second maybe-principal)))
             (setf (current-principal) (make-instance 'principal
                                                      :name user
                                                      :roles (third maybe-principal)))))))

     (claw-server-register-configuration *demo-server* "demo" (make-instance 'demo-configuration))

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda () (format nil
                           "<html>
                               <head>
                                 <title>protected resource</title>
                               <head>
                               <body>
                                 <h3><a href='logout.html'>logout</a></h3>
                                 <h2>Welcome ~a</h2>
                                 ~@[~a~]
                               </body>
                             </html>"
                           (principal-name (current-principal))
                           (when (user-in-role-p '("admin-role"))
                             "<h3>You are an administrator now!</h3>")))
      "protected.html")

     (lisplet-protect *sample-lisplet* "protected.html" '("admin-role" "user-role"))

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda ()
          (configuration-login (current-config))
          (if (current-principal)
              (claw-redirect "protected.html")
              "<html>
                 <head>
                   <title>A very simple page</title>
                 <head>
                 <body>
                   <h1>User login</h1>
                   <form method='post'>
                     username <input type='text' name='username'>
                     password <input type='password' name='password'>
                     <input type='submit' name='submit' value='Login'>
                   </form>
                 </body>
               </html>"))
      "login.html"
      :login-page-p t)

     (lisplet-register-function-location
      *sample-lisplet*
      #'(lambda ()
          (claw-remove-session)
          (claw-redirect "index.html"))
      "logout.html")

Of course you can protect entire branches of your applications, this is done by protecting the uri location, for example to protect all resources in the 'private' forlder.

     (lisplet-protect *sample-lisplet* "private/" '("admin-role" "user-role"))

HTTPS connections
=================

claw is able to pass connection over the HTTPS protocol and to manage sessions and services between HTTP and HTTPS.

To make the server listen for incoming https requests you will have to provide it at least a sslport

With the hunhcentoot connector if you don't pass through Apache mod_proxy you'll also have to pass it ssl-certificate-file, ssl-privatekey-file and , eventually, a ssl-privatekey-password parameter if the certificate is password protected. Of course you can also use Apache SSL certificate files.

To generate your own certificate files under Linux operating system, you can use openssl as described below.

First generate the private key file:

     #> openssl genrsa -out privkey.pem 2048

     Generating RSA private key, 2048 bit long modulus
     ............................+++
     ..................................................+++
     e is 65537 (0x10001)

     #>

Then the certificate file:

     #> openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095

     You are about to be asked to enter information that will be incorporated
     into your certificate request.
     What you are about to enter is what is called a Distinguished Name or a DN.
     There are quite a few fields but you can leave some blank
     For some fields there will be a default value,
     If you enter '.', the field will be left blank.
     -----
     Country Name (2 letter code) [AU]:IT
     State or Province Name (full name) [Some-State]: bla-bla
     Locality Name (eg, city) []: bla-bla
     Organization Name (eg, company) [Internet Widgits Pty Ltd]: mycompany
     Organizational Unit Name (eg, section) []:
     Common Name (eg, YOUR name) []:www.mycompany.com
     Email Address []:admin@mycompany.com

     #>

At this point you can instantiate the connector to directly handle HTTPS requests in the following way:

     (defvar *ht-connector*
       (make-instance 'hunchentoot-connector
                      :address "localhost"
                      :port 4242
                      :sslport 4343
                      :ssl-certificate-file #P "/PATH_TO_CERT_FILES/cacert.pem"
                      :ssl-privatekey-file #P "/PATH_TO_CERT_FILES/privkey.pem"))

If you plan to pass connections through Apache mod_proxy there is no need to enable ssl at CLAW level so it is sufficient to only set port and sslport.

Another great feature of the claw application server is the ability to automatically redirect requests to protected resources through the HTTPS protocol. This is done extremely easy by setting the REDIRECT-PROTECTED-RESOURCES-P lisplet parameter to true like in the following example

     (defvar *sample-lisplet*
       (make-instance 'lisplet :realm "demo"
                      :redirect-protected-resources-p t
                      :base-path "/demo"))

So all the resources mapped with LISPLET-PROTECT (and the login page in a form based authentication) will be redirected to the HTTPS protocol.