Change authentication scheme from Form based auth to OpenID + OAuth.

git-svn-id: https://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk@1201614 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/.gitignore b/.gitignore
index 0a161b3..1dd44f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,7 +56,7 @@
 config.guess
 config.sub
 config.status
-*config.js
+config.js
 all.js
 *-min.html
 *-min.js
@@ -93,7 +93,7 @@
 *.jar
 *.prefix
 *.crt
-*.patch
+/*.patch
 index.yaml
 core
 gen-cpp/
@@ -135,7 +135,7 @@
 js-test
 js-eval
 file-test
-test-start
+test-start*
 xml-value
 value-xml
 json-value
diff --git a/README b/README
index d532fe6..92dfde8 100644
--- a/README
+++ b/README
@@ -15,9 +15,9 @@
 Cache: key/value memory cache, using Memcached;
 Chat: XMPP chat, using Apache Vysper and Libstrophe;
 Constdb: fast persistent store for mostly constant data, using TinyCDB;
-Filedb: key/value 'NoSQL' persistent store, using plain files;
+Filedb: key/value persistent store, using plain files;
 Http: HTTP client, using Libcurl;
-Kvdb: fast key/value 'NoSQL' persistent store, using LevelDB;
+Kvdb: fast key/value persistent store, using LevelDB;
 Log: distributed logger, using Facebook Scribe;
 Queue: AMQP queuing, using Apache Qpid/C;
 Sqldb: SQL database, using PostgreSQL;
@@ -77,9 +77,9 @@
  |   |   |-- cache            Memcached key/value cache
  |   |   |-- chat             XMPP chat
  |   |   |-- constdb          TinyCDB constant persistent store
- |   |   |-- filedb           Plain file NoSQL persistent store
+ |   |   |-- filedb           Plain file persistent store
  |   |   |-- http             HTTP client
- |   |   |-- kvdb             LevelDB NoSQL persistent store
+ |   |   |-- kvdb             LevelDB key/value persistent store
  |   |   |-- log              Scribe logger
  |   |   |-- queue            AMQP message queue
  |   |   |-- sqldb            PostgreSQL database
@@ -98,6 +98,7 @@
  |   |
  |   |-- macos                Automated install on Mac OS X 10.1.7
  |   |-- ubuntu               Automated install on Ubuntu 10.10
+ |   |-- patches              Temporary patches to some of the dependencies
  |
  |-- branches                 Topic and release branches
  |
diff --git a/macos/macos-install b/macos/macos-install
index 2cc8a57..b947448 100755
--- a/macos/macos-install
+++ b/macos/macos-install
@@ -105,7 +105,8 @@
 tar xzf memcached-1.4.7.tar.gz
 cd memcached-1.4.7
 # http://code.google.com/p/memcached/issues/detail?id=218
-patch -p0<$build/../memcached-1.4.7.patch
+curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/memcached-1.4.7.patch
+patch -p0 <memcached-1.4.7.patch
 autoreconf --install
 ./configure --with-libevent=$build/libevent-2.0.13-stable-bin --prefix=$build/memcached-1.4.7-bin
 make
@@ -265,10 +266,13 @@
     exit $?
 fi
 cd $build
-curl -L http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/modsecurity-crs_2.2.1.tar.gz/download -o modsecurity-crs_2.2.1.tar.gz 
-tar xzf modsecurity-crs_2.2.1.tar.gz
-cp -R $build/modsecurity-crs_2.2.1/base_rules $build/modsecurity-apache-2.6.1-bin
-cp -R $build/modsecurity-crs_2.2.1/optional_rules $build/modsecurity-apache-2.6.1-bin
+curl -L http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/modsecurity-crs_2.2.2.tar.gz/download -o modsecurity-crs_2.2.2.tar.gz 
+tar xzf modsecurity-crs_2.2.2.tar.gz
+cd modsecurity-crs_2.2.2
+curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/modsecurity-crs_2.2.2.patch
+patch -p0 <modsecurity-crs_2.2.2.patch
+cp -R base_rules $build/modsecurity-apache-2.6.1-bin
+cp -R optional_rules $build/modsecurity-apache-2.6.1-bin
 if [ "$?" != "0" ]; then
     exit $?
 fi
@@ -305,7 +309,7 @@
 cd $build
 
 # Create src archive
-tar czf tuscany-sca-cpp-1.0-src.tar.gz apache-libcloud-incubating-0.4.2 apache-libcloud-incubating-0.4.2.tar.bz2 apr-1.4.x apr-1.4.x-bin autoconf-2.13 autoconf-2.13-bin autoconf-2.13.tar.gz curl-7.19.5 curl-7.19.5-bin curl-7.19.5.tar.gz expat-2.0.1 expat-2.0.1-bin expat-2.0.1.tar.gz htmltidy-bin httpd-2.3.15-beta httpd-2.3.15-beta.tar.gz httpd-2.3.15-bin js-1.8.5-bin js-1.8.5 js185-1.0.0.tar.gz libcloud-0.4.2-bin libevent-2.0.13-stable libevent-2.0.13-stable-bin libevent-2.0.13-stable.tar.gz liboauth-0.9.1 liboauth-0.9.1-bin liboauth-0.9.1.tar.gz libopkele libopkele-bin libstrophe libstrophe-bin libxml2-2.7.7 libxml2-2.7.7-bin libxml2-sources-2.7.7.tar.gz memcached-1.4.7 memcached-1.4.7-bin memcached-1.4.7.tar.gz mod_auth_openid mod-auth-openid-bin modsecurity-apache_2.6.1 modsecurity-apache-2.6.0-bin modsecurity-apache_2.6.0.tar.gz modsecurity-crs_2.2.1 modsecurity-crs_2.2.1.tar.gz nspr-4.8.8-bin nspr-4.8.8 nspr-4.8.8.tar.gz nuvem pcre-8.12 pcre-8.12-bin pcre-8.12.zip pkg-config-0.25 pkg-config-0.25-bin pkg-config-0.25.tar.gz tidy tinycdb tinycdb-bin leveldb tuscany-sca-cpp tuscany-sca-cpp-bin
+tar czf tuscany-sca-cpp-1.0-src.tar.gz apache-libcloud-incubating-0.4.2 apache-libcloud-incubating-0.4.2.tar.bz2 apr-1.4.x apr-1.4.x-bin autoconf-2.13 autoconf-2.13-bin autoconf-2.13.tar.gz curl-7.19.5 curl-7.19.5-bin curl-7.19.5.tar.gz expat-2.0.1 expat-2.0.1-bin expat-2.0.1.tar.gz htmltidy-bin httpd-2.3.15-beta httpd-2.3.15-beta.tar.gz httpd-2.3.15-bin js-1.8.5-bin js-1.8.5 js185-1.0.0.tar.gz libcloud-0.4.2-bin libevent-2.0.13-stable libevent-2.0.13-stable-bin libevent-2.0.13-stable.tar.gz liboauth-0.9.1 liboauth-0.9.1-bin liboauth-0.9.1.tar.gz libopkele libopkele-bin libstrophe libstrophe-bin libxml2-2.7.7 libxml2-2.7.7-bin libxml2-sources-2.7.7.tar.gz memcached-1.4.7 memcached-1.4.7-bin memcached-1.4.7.tar.gz mod_auth_openid mod-auth-openid-bin modsecurity-apache_2.6.1 modsecurity-apache-2.6.0-bin modsecurity-apache_2.6.0.tar.gz modsecurity-crs_2.2.2 modsecurity-crs_2.2.2.tar.gz nspr-4.8.8-bin nspr-4.8.8 nspr-4.8.8.tar.gz nuvem pcre-8.12 pcre-8.12-bin pcre-8.12.zip pkg-config-0.25 pkg-config-0.25-bin pkg-config-0.25.tar.gz tidy tinycdb tinycdb-bin leveldb tuscany-sca-cpp tuscany-sca-cpp-bin
 
 # Create bin archive
 tar czf tuscany-sca-cpp-1.0.tar.gz apr-1.4.x-bin curl-7.19.5-bin expat-2.0.1-bin htmltidy-bin httpd-2.3.15-bin js-1.8.5-bin libcloud-0.4.2-bin libevent-2.0.13-stable-bin liboauth-0.9.1-bin libopkele-bin libstrophe-bin libxml2-2.7.7-bin memcached-1.4.7-bin mod-auth-openid-bin modsecurity-apache-2.6.1-bin nspr-4.8.8-bin nuvem/nuvem-parallel pcre-8.12-bin tinycdb-bin leveldb tuscany-sca-cpp tuscany-sca-cpp-bin
diff --git a/modules/edit/Makefile.am b/modules/edit/Makefile.am
index b6a6fc9..98c0ecc 100644
--- a/modules/edit/Makefile.am
+++ b/modules/edit/Makefile.am
@@ -20,16 +20,16 @@
 moddir = $(prefix)/modules/edit
 dist_mod_SCRIPTS = start stop ssl-start mkapplinks
 
-BUILT_SOURCES = htdocs/headconfig.js htdocs/footconfig.js
-htdocs/headconfig.js:
-	touch htdocs/headconfig.js
+BUILT_SOURCES = htdocs/config.js htdocs/public/config.js
+htdocs/config.js:
+	touch htdocs/config.js
 
-htdocs/footconfig.js:
-	touch htdocs/footconfig.js
+htdocs/public/config.js:
+	touch htdocs/public/config.js
 
-not_minified = htdocs/public/iframe.html htdocs/create/index.html htdocs/page/index.html htdocs/login/index.html htdocs/notfound/index.html htdocs/oops/index.html htdocs/graph/index.html htdocs/notauth/index.html htdocs/account/index.html htdocs/home/index.html htdocs/index.html htdocs/notyet/index.html htdocs/clone/index.html htdocs/stats/index.html htdocs/app/index.html htdocs/logout/index.html htdocs/store/index.html htdocs/headconfig.js htdocs/footconfig.js
+not_minified = htdocs/public/iframe.html htdocs/create/index.html htdocs/page/index.html htdocs/login/index.html htdocs/public/notfound/index.html htdocs/public/oops/index.html htdocs/graph/index.html htdocs/public/notauth/index.html htdocs/account/index.html htdocs/home/index.html htdocs/index.html htdocs/public/notyet/index.html htdocs/clone/index.html htdocs/stats/index.html htdocs/app/index.html htdocs/logout/index.html htdocs/store/index.html htdocs/config.js htdocs/public/config.js
 
-minified = htdocs/public/iframe-min.html htdocs/create/index-min.html htdocs/page/index-min.html htdocs/login/index-min.html htdocs/notfound/index-min.html htdocs/oops/index-min.html htdocs/graph/index-min.html htdocs/notauth/index-min.html htdocs/account/index-min.html htdocs/home/index-min.html htdocs/index-min.html htdocs/notyet/index-min.html htdocs/clone/index-min.html htdocs/stats/index-min.html htdocs/app/index-min.html htdocs/logout/index-min.html htdocs/store/index-min.html htdocs/headconfig-min.js htdocs/footconfig-min.js
+minified = htdocs/public/iframe-min.html htdocs/create/index-min.html htdocs/page/index-min.html htdocs/login/index-min.html htdocs/public/notfound/index-min.html htdocs/public/oops/index-min.html htdocs/graph/index-min.html htdocs/public/notauth/index-min.html htdocs/account/index-min.html htdocs/home/index-min.html htdocs/index-min.html htdocs/public/notyet/index-min.html htdocs/clone/index-min.html htdocs/stats/index-min.html htdocs/app/index-min.html htdocs/logout/index-min.html htdocs/store/index-min.html htdocs/config-min.js htdocs/public/config-min.js
 
 resources = edit.composite *.py htdocs/*.cmf htdocs/*.ico htdocs/home/*.png htdocs/app/*.cmf htdocs/home/*.b64 htdocs/*.txt htdocs/public/*.png htdocs/public/*.b64 palettes/*/palette.composite accounts/*/*.account apps/*/app.composite apps/*/app.stats apps/*/htdocs/app.html dashboards/*/user.apps store/*/store.apps ${not_minified} ${minified}
 
diff --git a/modules/edit/accounts.py b/modules/edit/accounts.py
index 600134c..4589f6c 100644
--- a/modules/edit/accounts.py
+++ b/modules/edit/accounts.py
@@ -25,7 +25,7 @@
 # Get the current user's account
 def get(id, user, cache):
     account = cache.get(accountid(user))
-    if isNil(account):
+    if isNil(account) or account is None:
         return ()
     return account
 
diff --git a/modules/edit/apps.py b/modules/edit/apps.py
index a820f96..35a4c79 100644
--- a/modules/edit/apps.py
+++ b/modules/edit/apps.py
@@ -56,7 +56,7 @@
     if isNil(id):
         return (("'feed", ("'title", "Apps"), ("'id", "apps")),)
     app = cache.get(appid(id));
-    if (isNil(app) or app is None):
+    if isNil(app) or app is None:
         return (("'entry", ("'title", car(id)), ("'id", car(id))),)
     return app
 
diff --git a/modules/edit/composites.py b/modules/edit/composites.py
index 7eb8593..87569a8 100644
--- a/modules/edit/composites.py
+++ b/modules/edit/composites.py
@@ -33,7 +33,7 @@
     if isNil(id):
         return (("'feed", ("'title", "Composites"), ("'id", "composites")),)
     app = cache.get(appid(id));
-    if (isNil(app) or app is None):
+    if isNil(app) or app is None:
         return (("'entry", ("'title", car(id)), ("'id", car(id))),)
     return (("'entry", ("'title", car(id)), ("'id", car(id)), ("'content", car(app))),)
 
diff --git a/modules/edit/dashboards.py b/modules/edit/dashboards.py
index 5e98c9c..f42106e 100644
--- a/modules/edit/dashboards.py
+++ b/modules/edit/dashboards.py
@@ -25,7 +25,7 @@
 # Get a dashboard from the cache
 def getdashboard(id, cache):
     dashboard = cache.get(id)
-    if isNil(dashboard):
+    if isNil(dashboard) or dashboard is None:
         return ()
     return dashboard
 
diff --git a/modules/edit/htdocs/app/cache-manifest.cmf b/modules/edit/htdocs/app/cache-manifest.cmf
index b478c7c..6ea5397 100644
--- a/modules/edit/htdocs/app/cache-manifest.cmf
+++ b/modules/edit/htdocs/app/cache-manifest.cmf
@@ -4,12 +4,12 @@
 
 # App resources
 /favicon.ico
-/notauth/
-/notfound/
-/notyet/
-/oops/
 /public/iframe-min.html
 /public/img.png
+/public/notauth/
+/public/notfound/
+/public/notyet/
+/public/oops/
 /public/touchicon.png
 
 NETWORK:
diff --git a/modules/edit/htdocs/app/index.html b/modules/edit/htdocs/app/index.html
index 97ea0a3..0b01c1d 100644
--- a/modules/edit/htdocs/app/index.html
+++ b/modules/edit/htdocs/app/index.html
@@ -48,6 +48,8 @@
     if (http.status == 200) {
         if (http.getResponseHeader("X-Login") != null) {
             if (log) log('http error', u, 'X-Login');
+            // Redirect to login page if not signed in
+            document.location = '/login/';
             return null;
         } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) {
             if (log) log('http error', u, 'No-Content');
@@ -57,6 +59,9 @@
         return http.responseText;
     }
     if (log) log('http error', u, http.status, http.statusText);
+    // Redirect to login page if not signed in
+    if (http.status == 403)
+        document.location = '/login/';
     return null;
 };
 
@@ -69,6 +74,10 @@
     document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css')));
 })();
 
+// Redirect to login page if not signed in
+if (document.location.protocol == 'https:' && !ui.signedin())
+    document.location = '/login/';
+
 </script>
 </head>
 <body class="delayed" onload="onload();">
@@ -77,7 +86,7 @@
 <div id="headdiv" class="hsection">
 <script type="text/javascript">
 (function() {
-$('headdiv').appendChild(ui.declareScript(appcache.get('/headconfig-min.js')));
+$('headdiv').appendChild(ui.declareScript(appcache.get('/config-min.js')));
 })();
 </script>
 </div>
@@ -117,8 +126,8 @@
 var appresources = [
     ['/all-min.js'],
     ['/ui-min.css'],
-    ['/footconfig-min.js'],
-    ['/headconfig-min.js'],
+    ['/config-min.js'],
+    ['/public/config-min.js']
 ];
 
 /**
@@ -889,11 +898,6 @@
 </script>
 
 <div id="footdiv" class="fsection">
-<script type="text/javascript">
-(function() {
-$('footdiv').appendChild(ui.declareScript(appcache.get('/footconfig-min.js')));
-})();
-</script>
 </div>
 
 </div>
diff --git a/modules/edit/htdocs/cache-manifest.cmf b/modules/edit/htdocs/cache-manifest.cmf
index 0be3e66..cb76f77 100644
--- a/modules/edit/htdocs/cache-manifest.cmf
+++ b/modules/edit/htdocs/cache-manifest.cmf
@@ -5,12 +5,12 @@
 # App resources
 /
 /favicon.ico
-/notauth/
-/notfound/
-/notyet/
-/oops/
 /public/iframe-min.html
 /public/img.png
+/public/notauth/
+/public/notfound/
+/public/notyet/
+/public/oops/
 /public/touchicon.png
 
 NETWORK:
diff --git a/modules/edit/htdocs/index.html b/modules/edit/htdocs/index.html
index 547c116..0a57717 100644
--- a/modules/edit/htdocs/index.html
+++ b/modules/edit/htdocs/index.html
@@ -48,6 +48,8 @@
     if (http.status == 200) {
         if (http.getResponseHeader("X-Login") != null) {
             if (log) log('http error', u, 'X-Login');
+            // Redirect to login page if not signed in
+            document.location = '/login/';
             return null;
         } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) {
             if (log) log('http error', u, 'No-Content');
@@ -57,6 +59,9 @@
         return http.responseText;
     }
     if (log) log('http error', u, http.status, http.statusText);
+    // Redirect to login page if not signed in
+    if (http.status == 403)
+        document.location = '/login/';
     return null;
 };
 
@@ -69,6 +74,10 @@
     document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css')));
 })();
 
+// Redirect to login page if not signed in
+if (document.location.protocol == 'https:' && !ui.signedin())
+    document.location = '/login/';
+
 </script>
 </head>
 <body class="delayed" onload="onload();">
@@ -77,7 +86,7 @@
 <div id="headdiv" class="hsection">
 <script type="text/javascript">
 (function() {
-$('headdiv').appendChild(ui.declareScript(appcache.get('/headconfig-min.js')));
+$('headdiv').appendChild(ui.declareScript(appcache.get('/config-min.js')));
 })();
 </script>
 </div>
@@ -117,13 +126,13 @@
     ['/account/', 'flip'],
     ['/clone/', 'flip'],
     ['/create/', 'flip'],
-    ['/footconfig-min.js'],
     ['/graph/', 'flip'],
-    ['/headconfig-min.js'],
+    ['/config-min.js'],
     ['/home/', 'right'],
     ['/home/home.b64'],
     ['/page/', 'flip'],
     ['/public/app.b64'],
+    ['/public/config-min.js'],
     ['/public/grid72.b64'],
     ['/public/iframe-min.html'],
     ['/public/img.b64'],
@@ -249,7 +258,9 @@
                         ui.menu('Stats', '/#view=stats&app=' + appname, '_view', view == 'stats'),
                         ui.menu('Page', '/#view=page&app=' + appname, '_view', view == 'page'),
                         ui.menu(isNil(config.compose)? 'Composition' : config.compose, '/#view=graph&app=' + appname, '_view', view == 'graph'))),
-        mklist(ui.menu('Account', '/#view=account', '_view', view == 'account'), ui.menu('Sign out', '/logout/', '_self', false)));
+        mklist(
+            ui.menu('Account', '/#view=account', '_view', view == 'account'),
+            ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false)));
 }
 
 /**
@@ -486,11 +497,6 @@
 </script>
 
 <div id="footdiv" class="fsection">
-<script type="text/javascript">
-(function() {
-$('footdiv').appendChild(ui.declareScript(appcache.get('/footconfig-min.js')));
-})();
-</script>
 </div>
 
 </div>
diff --git a/modules/edit/htdocs/login/index.html b/modules/edit/htdocs/login/index.html
index 76709af..982f8cf 100644
--- a/modules/edit/htdocs/login/index.html
+++ b/modules/edit/htdocs/login/index.html
@@ -32,7 +32,8 @@
 
 <h1>Sign in</h1>
 
-<form name="formSignin" onsubmit="submitSignin();" method="POST" action="/login/dologin/">
+<!--
+<form name="passwordSignin" onsubmit="submitPasswordSignin();" method="POST" action="/login/dologin/">
 <table border="0">
 <tr><td><b>Username:</b></td></tr>
 <tr><td><input type="text" id="httpd_username" name="httpd_username" value="" size="15" autocapitalize="off" placeholder="Enter your user name" style="width: 300px;"/></td></tr>
@@ -42,6 +43,33 @@
 </table>
 <input type="hidden" name="httpd_location" value="/"/>
 </form>
+-->
+
+<form name="openIDForm">
+<table border="0">
+<tr><td><b>Sign in with your Google account</b></td></tr>
+<tr><td><input type="button" value="Sign in" class="graybutton" style="font-weight: bold;" onclick="submitOpenIDSignin(withGoogle)"/></td></tr>
+</table>
+</form>
+
+<form name="oauth2Form">
+<table border="0">
+<tr><td><b>Sign in with your Facebook account</b></td></tr>
+<tr><td><input type="button"  value="Sign in" class="graybutton" style="font-weight: bold;" onclick="submitOAuth2Signin(withFacebook)"/></td></tr>
+</table>
+</form>
+
+<form name="openIDSignin" action="/" method="GET">
+<input type="hidden" name="openid_identifier" value=""/>
+</form>
+
+<form name="oauth2Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth2_authorize" value=""/>
+<input type="hidden" name="mod_oauth2_access_token" value=""/>
+<input type="hidden" name="mod_oauth2_client_id" value=""/>
+<input type="hidden" name="mod_oauth2_info" value=""/>
+<input type="hidden" name="mod_oauth2_step" value="authorize"/>
+</form>
 
 <script type="text/javascript">
 function queryParams() {
@@ -55,7 +83,7 @@
     return qp;
 }
 
-function oauthReferrer() {
+function formReferrer() {
     r = queryParams()['openauth_referrer'];
     if (typeof(r) == 'undefined')
         return '/';
@@ -68,11 +96,68 @@
     return r;
 }
 
-function submitSignin() {
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/';
+function openauthReferrer() {
+    r = queryParams()['openauth_referrer'];
+    if (typeof(r) == 'undefined')
+        return '/';
+    q = r.indexOf('?');
+    if (q > 0)
+        return r.substring(0, q);
+    return r;
+}
+
+/**
+ * Signin with a userid and password.
+ */
+function submitPasswordSignin() {
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/';
     document.cookie = reset;
-    document.formSignin.httpd_location.value = oauthReferrer();
-    document.formSignin.submit();
+    localStorage.removeItem('/r/EditWidget/accounts');
+    localStorage.removeItem('/r/EditWidget/dashboards');
+    //localStorage.clear();
+    document.passwordSignin.httpd_location.value = formReferrer();
+    document.passwordSignin.submit();
+}
+
+/**
+ * Signin with OpenID.
+ */
+function submitOpenIDSignin(w) {
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/';
+    document.cookie = reset;
+    localStorage.removeItem('/r/EditWidget/accounts');
+    localStorage.removeItem('/r/EditWidget/dashboards');
+    //localStorage.clear();
+    document.openIDSignin.openid_identifier.value = w();
+    document.openIDSignin.action = openauthReferrer();
+    document.openIDSignin.submit();
+}
+
+function withGoogle() {
+    return 'https://www.google.com/accounts/o8/id';
+}
+
+/**
+ * Signin with OAuth 2.0.
+ */
+function submitOAuth2Signin(w) {
+    parms = w();
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/';
+    document.cookie = reset;
+    localStorage.removeItem('/r/EditWidget/accounts');
+    localStorage.removeItem('/r/EditWidget/dashboards');
+    //localStorage.clear();
+    document.oauth2Signin.mod_oauth2_authorize.value = parms[0];
+    document.oauth2Signin.mod_oauth2_access_token.value = parms[1];
+    document.oauth2Signin.mod_oauth2_client_id.value = parms[2];
+    document.oauth2Signin.mod_oauth2_info.value = parms[3];
+    document.oauth2Signin.action = openauthReferrer();
+    document.oauth2Signin.submit();
+}
+
+function withFacebook() {
+    var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'facebook.com', 'https://graph.facebook.com/me'];
+    return parms;
 }
 
 /**
diff --git a/modules/edit/htdocs/logout/index.html b/modules/edit/htdocs/logout/index.html
index f5dd06e..133b6b7 100644
--- a/modules/edit/htdocs/logout/index.html
+++ b/modules/edit/htdocs/logout/index.html
@@ -32,16 +32,18 @@
 
 <h1>Sign out</h1>
 
-<form name="signout" onsubmit="submitSignout();" action="/" method="GET">
+<form name="signout" onsubmit="submitSignout();" action="/login/" method="GET">
 <input type="submit" id="signOut" value="Sign out" class="graybutton" style="font-weight: bold"/>
 </form>
 
 <script type="text/javascript">
 function submitSignout() {
-    // Clear session cookie and local storage
+    // Clear session cookie and user-specific local storage entries
     var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/';
     document.cookie = reset;
-    localStorage.clear();
+    localStorage.removeItem('/r/EditWidget/accounts');
+    localStorage.removeItem('/r/EditWidget/dashboards');
+    //localStorage.clear();
     document.signout.submit();
     return true;
 }
diff --git a/modules/edit/htdocs/notauth/index.html b/modules/edit/htdocs/public/notauth/index.html
similarity index 89%
rename from modules/edit/htdocs/notauth/index.html
rename to modules/edit/htdocs/public/notauth/index.html
index b44ccb2..8a688c9 100644
--- a/modules/edit/htdocs/notauth/index.html
+++ b/modules/edit/htdocs/public/notauth/index.html
@@ -76,7 +76,7 @@
 <div id="headdiv" class="hsection">
 <script type="text/javascript">
 (function() {
-$('headdiv').appendChild(ui.declareScript(appcache.get('/headconfig-min.js')));
+$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')));
 })();
 </script>
 </div>
@@ -109,8 +109,8 @@
  */
 function showmenu(mdiv) {
     mdiv.innerHTML = ui.menubar(
-        mklist(ui.menu('Home', '/', '_view', false), ui.menu('Store', '/#view=store', '_view', false)),
-            mklist(ui.menu('Account', '/#view=account', '_view', false), ui.menu('Sign out', '/logout/', '_self', false)));
+        mklist(ui.menu('Home', '/', '_view', false)),
+            mklist(ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false)));
 }
 
 showmenu(mdiv);
@@ -145,11 +145,6 @@
 </script>
 
 <div id="footdiv" class="fsection">
-<script type="text/javascript">
-(function() {
-$('footdiv').appendChild(ui.declareScript(appcache.get('/footconfig-min.js')));
-})();
-</script>
 </div>
 
 </div>
diff --git a/modules/edit/htdocs/notfound/index.html b/modules/edit/htdocs/public/notfound/index.html
similarity index 89%
rename from modules/edit/htdocs/notfound/index.html
rename to modules/edit/htdocs/public/notfound/index.html
index 6b3bb09..b7ba34c 100644
--- a/modules/edit/htdocs/notfound/index.html
+++ b/modules/edit/htdocs/public/notfound/index.html
@@ -76,7 +76,7 @@
 <div id="headdiv" class="hsection">
 <script type="text/javascript">
 (function() {
-$('headdiv').appendChild(ui.declareScript(appcache.get('/headconfig-min.js')));
+$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')));
 })();
 </script>
 </div>
@@ -110,8 +110,8 @@
  */
 function showmenu(mdiv) {
     mdiv.innerHTML = ui.menubar(
-        mklist(ui.menu('Home', '/', '_view', false), ui.menu('Store', '/#view=store', '_view', false)),
-            mklist(ui.menu('Account', '/#view=account', '_view', false), ui.menu('Sign out', '/logout/', '_self', false)));
+        mklist(ui.menu('Home', '/', '_view', false)),
+            mklist(ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false)));
 }
 
 showmenu(mdiv);
@@ -146,11 +146,6 @@
 </script>
 
 <div id="footdiv" class="fsection">
-<script type="text/javascript">
-(function() {
-$('footdiv').appendChild(ui.declareScript(appcache.get('/footconfig-min.js')));
-})();
-</script>
 </div>
 
 </div>
diff --git a/modules/edit/htdocs/notyet/index.html b/modules/edit/htdocs/public/notyet/index.html
similarity index 89%
rename from modules/edit/htdocs/notyet/index.html
rename to modules/edit/htdocs/public/notyet/index.html
index d01e535..ca164f3 100644
--- a/modules/edit/htdocs/notyet/index.html
+++ b/modules/edit/htdocs/public/notyet/index.html
@@ -76,7 +76,7 @@
 <div id="headdiv" class="hsection">
 <script type="text/javascript">
 (function() {
-$('headdiv').appendChild(ui.declareScript(appcache.get('/headconfig-min.js')));
+$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')));
 })();
 </script>
 </div>
@@ -110,8 +110,8 @@
  */
 function showmenu(mdiv) {
     mdiv.innerHTML = ui.menubar(
-        mklist(ui.menu('Home', '/', '_view', false), ui.menu('Store', '/#view=store', '_view', false)),
-            mklist(ui.menu('Account', '/#view=account', '_view', false), ui.menu('Sign out', '/logout/', '_self', false)));
+        mklist(ui.menu('Home', '/', '_view', false)),
+            mklist(ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false)));
 }
 
 showmenu(mdiv);
@@ -146,11 +146,6 @@
 </script>
 
 <div id="footdiv" class="fsection">
-<script type="text/javascript">
-(function() {
-$('footdiv').appendChild(ui.declareScript(appcache.get('/footconfig-min.js')));
-})();
-</script>
 </div>
 
 </div>
diff --git a/modules/edit/htdocs/oops/index.html b/modules/edit/htdocs/public/oops/index.html
similarity index 89%
rename from modules/edit/htdocs/oops/index.html
rename to modules/edit/htdocs/public/oops/index.html
index aeb5ae5..8cfe2f6 100644
--- a/modules/edit/htdocs/oops/index.html
+++ b/modules/edit/htdocs/public/oops/index.html
@@ -76,7 +76,7 @@
 <div id="headdiv" class="hsection">
 <script type="text/javascript">
 (function() {
-$('headdiv').appendChild(ui.declareScript(appcache.get('/headconfig-min.js')));
+$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')));
 })();
 </script>
 </div>
@@ -109,8 +109,8 @@
  */
 function showmenu(mdiv) {
     mdiv.innerHTML = ui.menubar(
-        mklist(ui.menu('Home', '/', '_view', false), ui.menu('Store', '/#view=store', '_view', false)),
-            mklist(ui.menu('Account', '/#view=account', '_view', false), ui.menu('Sign out', '/logout/', '_self', false)));
+        mklist(ui.menu('Home', '/', '_view', false)),
+            mklist(ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false)));
 }
 
 showmenu(mdiv);
@@ -145,11 +145,6 @@
 </script>
 
 <div id="footdiv" class="fsection">
-<script type="text/javascript">
-(function() {
-$('footdiv').appendChild(ui.declareScript(appcache.get('/footconfig-min.js')));
-})();
-</script>
 </div>
 
 </div>
diff --git a/modules/edit/pages.py b/modules/edit/pages.py
index aa84f40..99392ae 100644
--- a/modules/edit/pages.py
+++ b/modules/edit/pages.py
@@ -33,7 +33,7 @@
     if isNil(id):
         return (("'feed", ("'title", "Pages"), ("'id", "pages")),)
     xhtml = cache.get(appid(id))
-    if (isNil(xhtml) or xhtml is None):
+    if isNil(xhtml) or xhtml is None:
         return (("'entry", ("'title", car(id)), ("'id", car(id))),)
     return (("'entry", ("'title", car(id)), ("'id", car(id)), ("'content", car(xhtml))),)
 
diff --git a/modules/edit/ssl-start b/modules/edit/ssl-start
index f467371..5103566 100755
--- a/modules/edit/ssl-start
+++ b/modules/edit/ssl-start
@@ -32,11 +32,30 @@
 ../../modules/http/httpd-event-conf tmp
 ../../modules/http/httpd-ssl-conf tmp 8453
 
-# Configure authentication
-../../modules/http/open-auth-conf tmp
-../../modules/http/passwd-auth-conf tmp john john
-../../modules/http/passwd-auth-conf tmp jane jane
-../../modules/http/passwd-auth-conf tmp admin admin
+# Configure password authentication
+#../../modules/http/open-auth-conf tmp
+#../../modules/http/passwd-auth-conf tmp john john
+#../../modules/http/passwd-auth-conf tmp jane jane
+#../../modules/http/passwd-auth-conf tmp admin admin
+
+# Configure OAuth authentication
+# Configure your OAuth app keys here
+../../modules/oauth/oauth-conf tmp
+../../modules/oauth/oauth-memcached-conf tmp sca-store.com 11212
+../../modules/oauth/oauth2-appkey-conf tmp facebook.com 12345 67890
+
+# Configure OpenID step2 authentication
+../../modules/openid/openid-conf tmp
+../../modules/openid/openid-step2-conf tmp
+../../modules/openid/openid-memcached-conf tmp sca-store.com 11212
+
+# Configure authorized users
+#../../modules/http/group-auth-conf tmp john
+#../../modules/http/group-auth-conf tmp jane
+#../../modules/http/group-auth-conf tmp admin
+# Configure your OpenID and OAuth ids here
+../../modules/http/group-auth-conf tmp https://www.google.com/accounts/o8/id?id=45678
+../../modules/http/group-auth-conf tmp 23456789
 
 # Configure mod-security
 ../../modules/http/mod-security-conf tmp
@@ -48,9 +67,10 @@
 # Configure error pages
 cat >>tmp/conf/svhost-ssl.conf <<EOF
 # Error pages
-ErrorDocument 404 /notfound/
-ErrorDocument 401 /notauth/
-ErrorDocument 500 /oops/
+ErrorDocument 404 /public/notfound/
+ErrorDocument 401 /public/notauth/
+ErrorDocument 500 /public/oops/
+ErrorDocument 405 /public/oops/
 
 EOF
 
@@ -100,8 +120,9 @@
 mkdir -p tmp/appdata/filedb
 
 # Start memcached
-../../components/cache/memcached-start
+../../components/cache/memcached-start 11211
+../../components/cache/memcached-start 11212
 
 # Start server
-../http/httpd-start tmp
+../../modules/http/httpd-start tmp
 
diff --git a/modules/edit/start b/modules/edit/start
index dfc6fa2..361cead 100755
--- a/modules/edit/start
+++ b/modules/edit/start
@@ -34,9 +34,10 @@
 # Configure error pages
 cat >>tmp/conf/svhost.conf <<EOF
 # Error pages
-ErrorDocument 404 /notfound/
-ErrorDocument 401 /notauth/
-ErrorDocument 500 /oops/
+ErrorDocument 404 /public/notfound/
+ErrorDocument 401 /public/notauth/
+ErrorDocument 500 /public/oops/
+ErrorDocument 405 /public/oops/
 
 EOF
 
@@ -86,7 +87,8 @@
 
 # Start memcached
 ../../components/cache/memcached-start 11211
+../../components/cache/memcached-start 11212
 
 # Start server
-../http/httpd-start tmp
+../../modules/http/httpd-start tmp
 
diff --git a/modules/edit/stop b/modules/edit/stop
index bc831c1..60c25f8 100755
--- a/modules/edit/stop
+++ b/modules/edit/stop
@@ -17,6 +17,7 @@
 #  specific language governing permissions and limitations
 #  under the License.
 
-../http/httpd-stop tmp
+../../modules/http/httpd-stop tmp
 ../../components/cache/memcached-stop 11211
+../../components/cache/memcached-stop 11212
 
diff --git a/modules/edit/store.py b/modules/edit/store.py
index eaa68b1..7975097 100644
--- a/modules/edit/store.py
+++ b/modules/edit/store.py
@@ -25,7 +25,7 @@
 # Get a store from the cache
 def getstore(id, cache):
     store = cache.get(id)
-    if isNil(store):
+    if isNil(store) or store is None:
         return ()
     return store
 
diff --git a/modules/http/httpd-conf b/modules/http/httpd-conf
index 516debd..67de40e 100755
--- a/modules/http/httpd-conf
+++ b/modules/http/httpd-conf
@@ -267,6 +267,11 @@
 Require all granted
 </Location>
 
+# Mark login page with a header
+<Location /login>
+Header set X-Login open-auth
+</Location>
+
 EOF
 
 # Create password and group files
diff --git a/modules/http/httpd.hpp b/modules/http/httpd.hpp
index d413e6c..c1cc16d 100644
--- a/modules/http/httpd.hpp
+++ b/modules/http/httpd.hpp
@@ -603,6 +603,7 @@
     debug(uri, "httpd::externalRedirect");
     r->status = HTTP_MOVED_TEMPORARILY;
     apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, c_str(uri)));
+    apr_table_setn(r->headers_out, "Cache-Control", "no-cache");
     r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/") + uri));
     return HTTP_MOVED_TEMPORARILY;
 }
diff --git a/modules/http/open-auth-conf b/modules/http/open-auth-conf
index bed20d7..66d3624 100755
--- a/modules/http/open-auth-conf
+++ b/modules/http/open-auth-conf
@@ -35,7 +35,7 @@
 AuthType Open
 AuthName "$host"
 Session On
-SessionCookieName TuscanyOpenAuth domain=.$host; path=/; max-age=31556926
+SessionCookieName TuscanyOpenAuth domain=.$host; path=/
 SessionCryptoPassphrase $pw
 AuthOpenAuth On
 AuthOpenAuthLoginPage /login
@@ -53,10 +53,5 @@
 SetHandler form-login-handler
 </Location>
 
-# Mark login page with a header
-<Location /login>
-Header set X-Login open-auth
-</Location>
-
 EOF
 
diff --git a/modules/http/openauth.hpp b/modules/http/openauth.hpp
index d737732..e044a74 100644
--- a/modules/http/openauth.hpp
+++ b/modules/http/openauth.hpp
@@ -77,7 +77,7 @@
     const time_t t = time(NULL) + 86400;
     char exp[32];
     strftime(exp, 32, "%a, %d-%b-%Y %H:%M:%S GMT", gmtime(&t));
-    const string c = string("TuscanyOpenAuth=") + sid + ";domain=." + domain + ";path=/;expires=" + string(exp) + ";secure=TRUE";
+    const string c = string("TuscanyOpenAuth=") + sid + "; expires=" + string(exp) + "; domain=." + domain + "; path=/";
     debug(c, "openauth::cookie");
     return c;
 }
diff --git a/modules/js/htdocs/ui.js b/modules/js/htdocs/ui.js
index d8628f6..ee65d62 100644
--- a/modules/js/htdocs/ui.js
+++ b/modules/js/htdocs/ui.js
@@ -193,6 +193,13 @@
 };
 
 /**
+ * Return true if the session cookie contains signin information.
+ */
+ui.signedin = function() {
+    return !isNil(document.cookie) && document.cookie.indexOf('TuscanyOpenAuth=') != -1;
+};
+
+/**
  * Convert a CSS position to a numeric position.
  */
 ui.numpos = function(p) {
diff --git a/modules/oauth/htdocs/login/index.html b/modules/oauth/htdocs/login/index.html
index 3805dea..d1002f7 100644
--- a/modules/oauth/htdocs/login/index.html
+++ b/modules/oauth/htdocs/login/index.html
@@ -57,7 +57,7 @@
 
 function submitSignin2(w) {
     parms = w();
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.signin2.mod_oauth2_authorize.value = parms[0];
     document.signin2.mod_oauth2_access_token.value = parms[1];
@@ -79,7 +79,7 @@
 
 function submitSignin1(w) {
     parms = w();
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.signin1.mod_oauth1_request_token.value = parms[0];
     document.signin1.mod_oauth1_authorize.value = parms[1];
diff --git a/modules/oauth/htdocs/login/mixed.html b/modules/oauth/htdocs/login/mixed.html
index 8be8a4d..57484dc 100644
--- a/modules/oauth/htdocs/login/mixed.html
+++ b/modules/oauth/htdocs/login/mixed.html
@@ -30,7 +30,7 @@
 
 <script type="text/javascript">
 function submitFormSignin() {
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.formSignin.httpd_location.value = '/';
     document.formSignin.submit();
@@ -62,7 +62,7 @@
 }
 
 function submitOpenIDSignin(w) {
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.openIDSignin.openid_identifier.value = w();
     document.openIDSignin.action = openauthReferrer();
@@ -111,7 +111,7 @@
 
 function submitOAuth2Signin(w) {
     parms = w();
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.oauth2Signin.mod_oauth2_authorize.value = parms[0];
     document.oauth2Signin.mod_oauth2_access_token.value = parms[1];
@@ -133,7 +133,7 @@
 
 function submitOAuth1Signin(w) {
     parms = w();
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.oauth1Signin.mod_oauth1_request_token.value = parms[0];
     document.oauth1Signin.mod_oauth1_authorize.value = parms[1];
diff --git a/modules/oauth/htdocs/logout/index.html b/modules/oauth/htdocs/logout/index.html
index 267c501..35172da 100644
--- a/modules/oauth/htdocs/logout/index.html
+++ b/modules/oauth/htdocs/logout/index.html
@@ -32,7 +32,7 @@
 <form name="signout" action="/login" method="GET">
 <script type="text/javascript">
 function submitSignout() {
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + window.location.hostname + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.signout.submit();
     return true;
diff --git a/modules/oauth/oauth-conf b/modules/oauth/oauth-conf
index 02f81a2..856eea7 100755
--- a/modules/oauth/oauth-conf
+++ b/modules/oauth/oauth-conf
@@ -41,6 +41,12 @@
 
 EOF
 
+cat >$root/cert/oauth-keys.conf <<EOF
+# Generated by: oauth-conf $*
+# OAuth App keys
+
+EOF
+
 cat >>$root/conf/auth.conf <<EOF
 # Generated by: oauth-conf $*
 # Enable OAuth authentication
@@ -54,13 +60,14 @@
 
 # Configure OAuth App keys
 Include $root/cert/oauth-keys.conf
+
+EOF
+
+if [ -d "$HOME/.oauth" ]; then
+    cat >>$root/conf/auth.conf <<EOF
+# Configure OAuth App keys
 Include $HOME/.oauth/*-key.conf
 
 EOF
-
-cat >$root/cert/oauth-keys.conf <<EOF
-# Generated by: oauth-conf $*
-# OAuth App keys
-
-EOF
+fi
 
diff --git a/modules/openid/htdocs/login/index.html b/modules/openid/htdocs/login/index.html
index a90b669..dcb10e1 100644
--- a/modules/openid/htdocs/login/index.html
+++ b/modules/openid/htdocs/login/index.html
@@ -56,7 +56,7 @@
 }
 
 function submitSignin(w) {
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.signin.openid_identifier.value = w();
     document.signin.action = openidReferrer();
diff --git a/modules/openid/htdocs/logout/index.html b/modules/openid/htdocs/logout/index.html
index 7780e9d..35172da 100644
--- a/modules/openid/htdocs/logout/index.html
+++ b/modules/openid/htdocs/logout/index.html
@@ -32,7 +32,7 @@
 <form name="signout" action="/login" method="GET">
 <script type="text/javascript">
 function submitSignout() {
-    var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
+    var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + window.location.hostname + '; path=/';
     document.cookie = reset;
     document.signout.submit();
     return true;
diff --git a/modules/openid/openid-conf b/modules/openid/openid-conf
index 4cc8bcd..021c8b1 100755
--- a/modules/openid/openid-conf
+++ b/modules/openid/openid-conf
@@ -44,8 +44,7 @@
 AuthOpenIDEnabled On
 AuthOpenIDCookiePath /
 AuthOpenIDCookieName TuscanyOpenAuth
-AuthOpenIDSecureCookie On
-AuthOpenIDLoginPage /login
+AuthOpenIDLoginPage /login/
 AuthOpenIDAXAdd EMAIL http://axschema.org/contact/email
 AuthOpenIDAXAdd FULLNAME http://axschema.org/namePerson
 AuthOpenIDAXAdd NICKNAME http://axschema.org/namePerson/friendly
diff --git a/macos/memcached-1.4.7.patch b/patches/memcached-1.4.7.patch
similarity index 100%
rename from macos/memcached-1.4.7.patch
rename to patches/memcached-1.4.7.patch
diff --git a/patches/modsecurity-crs_2.2.2.patch b/patches/modsecurity-crs_2.2.2.patch
new file mode 100644
index 0000000..2ff56de
--- /dev/null
+++ b/patches/modsecurity-crs_2.2.2.patch
@@ -0,0 +1,8 @@
+--- base_rules/modsecurity_crs_40_generic_attacks.conf
++++ base_rules/modsecurity_crs_40_generic_attacks.conf
+164,165c164,165
+< SecRule ARGS "(?:ft|htt)ps?.*\?+$" \
+<         "phase:2,rev:'2.2.2',t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,status:501,msg:'Remote File Inclusion Attack',id:'950119',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.rfi_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/RFI-%{matched_var_name}=%{tx.0}"
+---
+> #SecRule ARGS "(?:ft|htt)ps?.*\?+$" \
+> #        "phase:2,rev:'2.2.2',t:none,t:htmlEntityDecode,t:lowercase,capture,ctl:auditLogParts=+E,block,status:501,msg:'Remote File Inclusion Attack',id:'950119',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},setvar:tx.rfi_score=+%{tx.critical_anomaly_score},setvar:tx.%{rule.id}-WEB_ATTACK/RFI-%{matched_var_name}=%{tx.0}"
diff --git a/ubuntu/ubuntu-install b/ubuntu/ubuntu-install
index 40023e3..7b46ee0 100755
--- a/ubuntu/ubuntu-install
+++ b/ubuntu/ubuntu-install
@@ -237,8 +237,11 @@
 cd $build
 curl -OL http://downloads.sourceforge.net/project/mod-security/modsecurity-crs/0-CURRENT/modsecurity-crs_2.2.2.tar.gz
 tar xzf modsecurity-crs_2.2.2.tar.gz
-cp -R $build/modsecurity-crs_2.2.2/base_rules $build/modsecurity-apache-2.6.1-bin
-cp -R $build/modsecurity-crs_2.2.2/optional_rules $build/modsecurity-apache-2.6.1-bin
+cd modsecurity-crs_2.2.2
+curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/modsecurity-crs_2.2.2.patch
+patch -p0 <modsecurity-crs_2.2.2.patch
+cp -R base_rules $build/modsecurity-apache-2.6.1-bin
+cp -R optional_rules $build/modsecurity-apache-2.6.1-bin
 if [ "$?" != "0" ]; then
     exit $?
 fi
diff --git a/ubuntu/ubuntu-install-all b/ubuntu/ubuntu-install-all
index ea3023e..fc07193 100755
--- a/ubuntu/ubuntu-install-all
+++ b/ubuntu/ubuntu-install-all
@@ -291,8 +291,11 @@
 cd $build
 curl -OL http://downloads.sourceforge.net/project/mod-security/modsecurity-crs/0-CURRENT/modsecurity-crs_2.2.2.tar.gz
 tar xzf modsecurity-crs_2.2.2.tar.gz
-cp -R $build/modsecurity-crs_2.2.2/base_rules $build/modsecurity-apache-2.6.1-bin
-cp -R $build/modsecurity-crs_2.2.2/optional_rules $build/modsecurity-apache-2.6.1-bin
+cd modsecurity-crs_2.2.2
+curl -OL http://svn.apache.org/repos/asf/tuscany/sca-cpp/trunk/patches/modsecurity-crs_2.2.2.patch
+patch -p0 <modsecurity-crs_2.2.2.patch
+cp -R base_rules $build/modsecurity-apache-2.6.1-bin
+cp -R optional_rules $build/modsecurity-apache-2.6.1-bin
 if [ "$?" != "0" ]; then
     exit $?
 fi