diff options
38 files changed, 1156 insertions, 367 deletions
diff --git a/sca-cpp/trunk/.gitignore b/sca-cpp/trunk/.gitignore index 539b8309ac..cb61e71d6c 100644 --- a/sca-cpp/trunk/.gitignore +++ b/sca-cpp/trunk/.gitignore @@ -148,6 +148,7 @@ hosting/server/nuvem hosting/server/lib hosting/server/data/apps/*/nuvem hosting/server/data/apps/*/lib +hosting/server/data/authn chat-send opencl-shell opencl-test diff --git a/sca-cpp/trunk/components/cache/memcached-ssl-test b/sca-cpp/trunk/components/cache/memcached-ssl-test index 8ef37a0b98..a9d42ffd83 100755 --- a/sca-cpp/trunk/components/cache/memcached-ssl-test +++ b/sca-cpp/trunk/components/cache/memcached-ssl-test @@ -29,6 +29,7 @@ rm -rf tmp ../../modules/http/httpd-conf tmp/tunnel localhost 8089 htdocs ../../modules/http/httpd-event-conf tmp/tunnel +../../modules/http/httpd-tunnel-ssl-conf tmp/tunnel tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C tmp/tunnel -x ../../modules/http/tunnel-ssl-conf tmp/tunnel 11211 localhost 8453 11411 ../../modules/http/tunnel-ssl-conf tmp/tunnel 11212 localhost 8453 11412 @@ -39,6 +40,7 @@ tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C tmp/tunnel ../../modules/http/httpd-event-conf tmp/server tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C tmp/server -x ../../modules/http/httpd-ssl-conf tmp/server 8453 +../../modules/http/httpd-tunnel-ssl-conf tmp/server ../../modules/http/cert-auth-conf tmp/server ../../modules/http/httpd-start tmp/server sleep 1 diff --git a/sca-cpp/trunk/hosting/server/Makefile.am b/sca-cpp/trunk/hosting/server/Makefile.am index d140895dcd..d6e15f819b 100644 --- a/sca-cpp/trunk/hosting/server/Makefile.am +++ b/sca-cpp/trunk/hosting/server/Makefile.am @@ -18,16 +18,18 @@ if WANT_PYTHON moddir = $(prefix)/hosting/server -dist_mod_SCRIPTS = start stop ssl-start mkapplinks config-backup data-backup +dist_mod_SCRIPTS = start stop ssl-start mkapplinks config-backup data-backup put-auth get-auth delete-auth -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/proxy/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/delete/index.html htdocs/stats/index.html htdocs/app/index.html htdocs/store/index.html htdocs/config.js htdocs/public/config.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/proxy/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/delete/index.html htdocs/stats/index.html htdocs/app/index.html htdocs/store/index.html htdocs/config.js htdocs/public/config.js htdocs/cache-template.cmf htdocs/app/cache-template.cmf htdocs/cache-template.cmf htdocs/app/cache-template.cmf 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/proxy/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/delete/index-min.html htdocs/stats/index-min.html htdocs/app/index-min.html htdocs/store/index-min.html htdocs/config-min.js htdocs/public/config-min.js -resources = server.composite *.py htdocs/*.cmf htdocs/*.ico htdocs/home/*.png htdocs/app/*.cmf htdocs/home/*.b64 htdocs/*.txt htdocs/public/*.png htdocs/public/*.b64 data/palettes/*/palette.composite data/accounts/*/*.account data/apps/*/app.composite data/apps/*/app.stats data/apps/*/htdocs/app.html data/dashboards/*/user.apps data/store/*/store.apps ${not_minified} ${minified} +js_minified = ../../modules/js/htdocs/all-min.js ../../modules/js/htdocs/ui-min.css + +resources = server.composite *.py data/palettes/*/palette.composite data/accounts/*/*.account data/apps/*/app.composite data/apps/*/app.stats data/apps/*/htdocs/app.html data/dashboards/*/user.apps data/store/*/store.apps htdocs/cache-manifest.cmf htdocs/app/cache-manifest.cmf htdocs/*.ico htdocs/home/*.png htdocs/home/*.b64 htdocs/*.txt htdocs/public/*.png htdocs/public/*.b64 ${minified} nobase_dist_mod_DATA = ${resources} -EXTRA_DIST = ${resources} +EXTRA_DIST = ${resources} ${not_minified} SUFFIXES = -min.html -min.js .html-min.html: @@ -36,9 +38,29 @@ SUFFIXES = -min.html -min.js .js-min.js: ../../modules/http/minify-js $< $@ -CLEANFILES = ${minified} +htdocs/cache-manifest.cmf: htdocs/cache-template.cmf ${minified} ${js_minified} + ../../modules/http/cache-manifest htdocs $^ + +htdocs/app/cache-manifest.cmf: htdocs/app/cache-template.cmf ${minified} ${js_minified} + ../../modules/http/cache-manifest htdocs/app $^ + +nuvem: + ln -s "../../../nuvem/nuvem-parallel/nuvem" "nuvem" + +lib: + ln -s "../../components" "lib" + +install-data-hook: + cd $(moddir); rm -f nuvem; ln -s "../../../nuvem/nuvem-parallel/nuvem" "nuvem" + cd $(moddir); rm -f lib; ln -s "../../components" "lib" + +CLEANFILES = ${minified} nuvem lib htdocs/cache-manifest.cmf htdocs/app/cache-manifest.cmf + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -dist_noinst_SCRIPTS = server-test test.py -TESTS = server-test +dist_noinst_SCRIPTS = logic-test server-test test.py +noinst_PROGRAMS = client-test +TESTS = logic-test endif diff --git a/sca-cpp/trunk/hosting/server/authn.py b/sca-cpp/trunk/hosting/server/authn.py new file mode 100644 index 0000000000..4d4f34b9fb --- /dev/null +++ b/sca-cpp/trunk/hosting/server/authn.py @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# User authenticator implementation +from time import strftime +from util import * + +# Convert a particular user id to an authentication id +def authnid(id): + return append(append(('authn',), id), ('user.authn',)) + +# Get a user's authentication +def get(id, cache): + authn = cache.get(authnid(id)) + if isNil(authn) or authn is None: + return None + return authn + +# Update a user's authentication +def put(id, authn, cache): + return cache.put(authnid(id), authn) + +# Delete a user's authentication +def delete(id, cache): + return cache.delete(authnid(id)) + diff --git a/sca-cpp/trunk/hosting/server/data/accounts/admin/user.account b/sca-cpp/trunk/hosting/server/data/accounts/admin/user.account new file mode 100644 index 0000000000..4f4a754a92 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/data/accounts/admin/user.account @@ -0,0 +1 @@ +((entry (title "Admin") (id "admin"))) diff --git a/sca-cpp/trunk/hosting/server/data/accounts/jane/user.account b/sca-cpp/trunk/hosting/server/data/accounts/jane/user.account new file mode 100644 index 0000000000..a3cf7e2c3d --- /dev/null +++ b/sca-cpp/trunk/hosting/server/data/accounts/jane/user.account @@ -0,0 +1 @@ +((entry (title "Jane Doe") (id "jane") (content (account (description "This is Jane") (keys (key (((@name "key1") (@value "value1")) ((@name "key2") (@value "value2")) ((@name "key3") (@value "value3")) ((@name "") (@value "")) ((@name "") (@value ""))))))))) diff --git a/sca-cpp/trunk/hosting/server/data/accounts/jane@localhost/user.account b/sca-cpp/trunk/hosting/server/data/accounts/jane@localhost/user.account deleted file mode 100644 index 5fca389f04..0000000000 --- a/sca-cpp/trunk/hosting/server/data/accounts/jane@localhost/user.account +++ /dev/null @@ -1 +0,0 @@ -((entry (title "Jane Doe") (id "jane@localhost"))) diff --git a/sca-cpp/trunk/hosting/server/data/accounts/jane@sca-store.com/user.account b/sca-cpp/trunk/hosting/server/data/accounts/jane@sca-store.com/user.account deleted file mode 100644 index e0d25671b6..0000000000 --- a/sca-cpp/trunk/hosting/server/data/accounts/jane@sca-store.com/user.account +++ /dev/null @@ -1 +0,0 @@ -((entry (title "Jane Doe") (id "jane@sca-store.com") (content (account (description "This is Jane") (keys (key (((@name "key1") (@value "value1")) ((@name "key2") (@value "value2")) ((@name "key3") (@value "value3")) ((@name "") (@value "")) ((@name "") (@value "")))))))))
\ No newline at end of file diff --git a/sca-cpp/trunk/hosting/server/data/accounts/john/user.account b/sca-cpp/trunk/hosting/server/data/accounts/john/user.account new file mode 100644 index 0000000000..9989daa228 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/data/accounts/john/user.account @@ -0,0 +1 @@ +((entry (title "John Doe") (id "john") (content (account (description "This is John") (keys (key (((@name "key1") (@value "value1")) ((@name "key2") (@value "value2")) ((@name "key3") (@value "value3")) ((@name "key4") (@value "value4")) ((@name "key5") (@value "value5"))))))))) diff --git a/sca-cpp/trunk/hosting/server/data/accounts/john@localhost/user.account b/sca-cpp/trunk/hosting/server/data/accounts/john@localhost/user.account deleted file mode 100644 index 35d6f30f0b..0000000000 --- a/sca-cpp/trunk/hosting/server/data/accounts/john@localhost/user.account +++ /dev/null @@ -1 +0,0 @@ -((entry (title "John Doe") (id "john@localhost"))) diff --git a/sca-cpp/trunk/hosting/server/data/accounts/john@sca-store.com/user.account b/sca-cpp/trunk/hosting/server/data/accounts/john@sca-store.com/user.account deleted file mode 100644 index 273335e1c7..0000000000 --- a/sca-cpp/trunk/hosting/server/data/accounts/john@sca-store.com/user.account +++ /dev/null @@ -1 +0,0 @@ -((entry (title "John Doe") (id "john@sca-store.com") (content (account (description "This is John") (keys (key (((@name "key1") (@value "value1")) ((@name "key2") (@value "value2")) ((@name "key3") (@value "value3")) ((@name "key4") (@value "value4")) ((@name "key5") (@value "value5")))))))))
\ No newline at end of file diff --git a/sca-cpp/trunk/hosting/server/delete-auth b/sca-cpp/trunk/hosting/server/delete-auth new file mode 100755 index 0000000000..407d730c80 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/delete-auth @@ -0,0 +1,61 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +admin=$2 +apass=$3 +user=$4 + +httpd_prefix=`cat $here/../../modules/http/httpd.prefix` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + scheme="http" + addr=`echo $conf | awk '{ print $7 }'` + host=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $addr` +else + scheme="https" + ssladdr=`echo $sslconf | awk '{ print $6 }'` + host=`$here/../../modules/http/httpd-addr ip $ssladdr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $ssladdr` +fi + +# Compute user id +slash=`echo $user | grep "/"` +if [ "$slash" = "" ]; then + id="\"$user\"" + upath=$user +else + id=`echo $user | awk -F "/" '{ printf "\"%s\" \"%s\"", $2, $3 }'` + upath=`echo $user | awk -F "/" '{ printf "%s/%s", $2, $3 }'` +fi + +# Delete user auth +curl -k -L -u $admin:$apass -X DELETE -H "X-Forwarded-Server: $host" $scheme://$host:$port/c/Authenticator/$upath + diff --git a/sca-cpp/trunk/hosting/server/get-auth b/sca-cpp/trunk/hosting/server/get-auth new file mode 100755 index 0000000000..2be546f91f --- /dev/null +++ b/sca-cpp/trunk/hosting/server/get-auth @@ -0,0 +1,62 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +admin=$2 +apass=$3 +user=$4 + +httpd_prefix=`cat $here/../../modules/http/httpd.prefix` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + scheme="http" + addr=`echo $conf | awk '{ print $7 }'` + host=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $addr` +else + scheme="https" + ssladdr=`echo $sslconf | awk '{ print $6 }'` + host=`$here/../../modules/http/httpd-addr ip $ssladdr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $ssladdr` +fi + +# Compute user id +slash=`echo $user | grep "/"` +if [ "$slash" = "" ]; then + id="\"$user\"" + upath=$user +else + id=`echo $user | awk -F "/" '{ printf "\"%s\" \"%s\"", $2, $3 }'` + upath=`echo $user | awk -F "/" '{ printf "%s/%s", $2, $3 }'` +fi + +# Get user auth +curl -k -L -u $admin:$apass -H "X-Forwarded-Server: $host" $scheme://$host:$port/c/Authenticator/$upath + diff --git a/sca-cpp/trunk/hosting/server/put-auth b/sca-cpp/trunk/hosting/server/put-auth new file mode 100755 index 0000000000..351c9b7d7a --- /dev/null +++ b/sca-cpp/trunk/hosting/server/put-auth @@ -0,0 +1,80 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` +admin=$2 +apass=$3 +user=$4 +upass=$5 + +httpd_prefix=`cat $here/../../modules/http/httpd.prefix` + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + scheme="http" + addr=`echo $conf | awk '{ print $7 }'` + host=`$here/../../modules/http/httpd-addr ip $addr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $addr` +else + scheme="https" + ssladdr=`echo $sslconf | awk '{ print $6 }'` + host=`$here/../../modules/http/httpd-addr ip $ssladdr` + if [ "$host" = "" ]; then + host="localhost" + fi + port=`$here/../../modules/http/httpd-addr port $ssladdr` +fi + +# Get password hash +rm -f $root/conf/auth.passwd +touch $root/conf/auth.passwd +$httpd_prefix/bin/htpasswd -b $root/conf/auth.passwd "$user" "$upass" 2>/dev/null +hash=`cat $root/conf/auth.passwd | awk -F ":" '{ print $2 }'` +rm -f $root/conf/auth.passwd + +# Compute user id +slash=`echo $user | grep "/"` +if [ "$slash" = "" ]; then + id="\"$user\"" + upath=$user +else + id=`echo $user | awk -F "/" '{ printf "\"%s\" \"%s\"", $2, $3 }'` + upath=`echo $user | awk -F "/" '{ printf "%s/%s", $2, $3 }'` +fi + +# Put user auth +cat >$root/conf/auth.entry <<EOF +<?xml version="1.0" encoding="UTF-8"?> +<entry xmlns="http://www.w3.org/2005/Atom"> + <title type="text">$user</title> + <id>$user</id> + <content type="application/xml"> + <hash>$hash</hash> + </content> +</entry> +EOF +curl -k -L -u $admin:$apass -X PUT -H "X-Forwarded-Server: $host" --data-binary @$root/conf/auth.entry $scheme://$host:$port/c/Authenticator/$upath +rm $root/conf/auth.entry + diff --git a/sca-cpp/trunk/hosting/server/server.composite b/sca-cpp/trunk/hosting/server/server.composite index 0806a2fa4b..7e4d7196d0 100644 --- a/sca-cpp/trunk/hosting/server/server.composite +++ b/sca-cpp/trunk/hosting/server/server.composite @@ -31,12 +31,9 @@ <property name="lastname">?</property> <property name="realm">?</property> <property name="host">?</property> - <service name="User"> - <binding.http uri="user"/> - </service> </component> - <component name="EditWidget"> + <component name="Editor"> <implementation.widget location="/index.html"/> <reference name="user" target="User"/> <reference name="accounts" target="Accounts"/> @@ -49,7 +46,7 @@ <reference name="log" target="Log"/> </component> - <component name="AppWidget"> + <component name="App"> <implementation.widget location="/app/index.html"/> <reference name="user" target="User"/> <reference name="pages" target="Pages"/> @@ -59,18 +56,17 @@ <component name="Accounts"> <implementation.python script="accounts.py"/> - <service name="Accounts"> - <binding.http uri="accounts"/> - </service> <reference name="user" target="User"/> <reference name="cache" target="Cache"/> </component> + <component name="Authenticator"> + <implementation.python script="authn.py"/> + <reference name="cache" target="Cache"/> + </component> + <component name="Dashboards"> <implementation.python script="dashboards.py"/> - <service name="Dashboards"> - <binding.http uri="dashboards"/> - </service> <reference name="user" target="User"/> <reference name="cache" target="Cache"/> <reference name="apps" target="Apps"/> @@ -78,9 +74,6 @@ <component name="AppStore"> <implementation.python script="store.py"/> - <service name="AppStore"> - <binding.http uri="appstore"/> - </service> <reference name="user" target="User"/> <reference name="cache" target="Cache"/> <reference name="apps" target="Apps"/> @@ -88,9 +81,6 @@ <component name="Apps"> <implementation.python script="apps.py"/> - <service name="Apps"> - <binding.http uri="apps"/> - </service> <reference name="user" target="User"/> <reference name="cache" target="Cache"/> <reference name="dashboard" target="Dashboards"/> @@ -101,9 +91,6 @@ <component name="Composites"> <implementation.python script="composites.py"/> - <service name="Composites"> - <binding.http uri="composites"/> - </service> <reference name="user" target="User"/> <reference name="cache" target="Doccache"/> <reference name="apps" target="Apps"/> @@ -111,9 +98,6 @@ <component name="Pages"> <implementation.python script="pages.py"/> - <service name="Pages"> - <binding.http uri="pages"/> - </service> <reference name="user" target="User"/> <reference name="cache" target="Doccache"/> <reference name="apps" target="Apps"/> @@ -121,17 +105,11 @@ <component name="Palettes"> <implementation.python script="palettes.py"/> - <service name="Palettes"> - <binding.http uri="palettes"/> - </service> <reference name="cache" target="Doccache"/> </component> <component name="Cache"> <implementation.cpp path="../../components/cache" library="libdatacache"/> - <service name="Cache"> - <binding.http uri="cache"/> - </service> <reference name="l1reader" target="Memcache"/> <reference name="l1writer" target="Memcache"/> <reference name="l2reader" target="Database"/> @@ -140,9 +118,6 @@ <component name="Doccache"> <implementation.cpp path="../../components/cache" library="libdatacache"/> - <service name="Doccache"> - <binding.http uri="doccache"/> - </service> <reference name="l1reader" target="Memcache"/> <reference name="l1writer" target="Memcache"/> <reference name="l2reader" target="Documents"/> @@ -151,9 +126,6 @@ <component name="Memcache"> <implementation.cpp path="../../components/cache" library="libmemcache"/> - <service name="Memcache"> - <binding.http uri="memcache"/> - </service> <property name="server">localhost:11211</property> <property name="server">localhost:11212</property> </component> @@ -162,25 +134,16 @@ <implementation.cpp path="../../components/filedb" library="libfiledb"/> <property name="dbname">data</property> <property name="format">scheme</property> - <service name="Database"> - <binding.http uri="database"/> - </service> </component> <component name="Documents"> <implementation.cpp path="../../components/filedb" library="libfiledb"/> <property name="dbname">data</property> <property name="format">xml</property> - <service name="Documents"> - <binding.http uri="documents"/> - </service> </component> <component name="Log"> <implementation.python script="log.py"/> - <service name="Log"> - <binding.http uri="log"/> - </service> </component> </composite> diff --git a/sca-cpp/trunk/hosting/server/ssl-start b/sca-cpp/trunk/hosting/server/ssl-start index b80b2adf40..d699089847 100755 --- a/sca-cpp/trunk/hosting/server/ssl-start +++ b/sca-cpp/trunk/hosting/server/ssl-start @@ -22,7 +22,6 @@ # 127.0.0.1 www.example.com here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` -jsprefix=`echo "import os; print os.path.realpath('$here/../../modules/js')" | python` host=`hostname` # Create SSL certificates @@ -41,39 +40,33 @@ fi ../../components/cache/memcached-start tmp 11211 ../../components/cache/memcached-start tmp 11212 +# Clear document cache +rm -rf tmp/cache + # Configure server ../../modules/http/httpd-conf tmp www.example.com 8090 htdocs +../../modules/http/alt-host-conf tmp ww1.example.com +../../modules/http/alt-host-conf tmp ww2.example.com ../../modules/http/httpd-event-conf tmp +#../../modules/http/cache-conf tmp ../../modules/http/httpd-ssl-conf tmp 8453 +#../../modules/http/cache-ssl-conf tmp # Configure HTTP basic auth -../../modules/http/basic-auth-conf tmp +../../modules/http/basic-auth-conf tmp component # Configure OAuth authentication # Configure your OAuth app keys here -../../modules/oauth/oauth-conf tmp +../../modules/oauth/oauth-conf tmp component ../../modules/oauth/oauth-memcached-conf tmp localhost 11212 ../../modules/oauth/oauth2-appkey-conf tmp facebook.com 12345 67890 ../../modules/oauth/oauth2-appkey-conf tmp google.com 12345 67890 -# 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 OpenID step2 authentication -../../modules/openid/openid-conf tmp -../../modules/openid/openid-step2-conf tmp -../../modules/openid/openid-memcached-conf tmp localhost 11212 +# Configure form-based authentication +../../modules/http/open-auth-conf tmp component 80b67f38-b79e-4a72-bb5c-22c69fb00820 -# 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 the email addresses associated with your OpenID and OAuth ids here -../../modules/http/group-auth-conf tmp john@example.com -../../modules/http/group-auth-conf tmp jane@example.com +# Configure authorized admins +../../modules/http/passwd-auth-conf tmp admin admin # Configure mod-security #../../modules/http/mod-security-conf tmp @@ -103,26 +96,6 @@ SecAuditLog "|$here/../../components/log/scribe-cat $host secaudit" EOF -else - cat >tmp/conf/log.conf <<EOF -# Generated by: ssl=start $* -ErrorLog $here/tmp/logs/error_log -CustomLog $here/tmp/logs/access_log combined - -EOF - - cat >tmp/conf/log-ssl.conf <<EOF -# Generated by: ssl-start $* -CustomLog $here/tmp/logs/ssl_access_log sslcombined - -EOF - - cat >tmp/conf/mod-security-log.conf <<EOF -# Generated by: ssl-start $* -SecAuditLog $here/tmp/logs/secaudit_log - -EOF - fi #../../modules/http/httpd-loglevel-conf tmp debug @@ -143,10 +116,11 @@ cat >>tmp/conf/svhost-ssl.conf <<EOF ErrorDocument 404 /public/notfound/ ErrorDocument 401 /public/notauth/ ErrorDocument 403 /public/notauth/ +ErrorDocument 400 /public/oops/ +ErrorDocument 405 /public/oops/ ErrorDocument 500 /public/oops/ ErrorDocument 502 /public/oops/ ErrorDocument 503 /public/oops/ -ErrorDocument 405 /public/oops/ EOF @@ -160,6 +134,12 @@ SCAComposite server.composite # Configure SCA Composite for mass dynamic virtual Hosting SCAVirtualContributor Composites +# Configure SCA Authenticator component +SCAAuthenticator Authenticator + +# Configure SCA wiring timeout +SCAWiringTimeout 10 + EOF # Configure resource aliases @@ -172,14 +152,6 @@ Alias /proxy/public/config-min.js $here/public/config-min.js EOF -# Create app implementation resource links -if [ ! -e "nuvem" ]; then - ln -s "../../../nuvem/nuvem-parallel/nuvem" "nuvem" -fi -if [ ! -e "lib" ]; then - ln -s "../../components" "lib" -fi - # Configure app resource aliases cat >>tmp/conf/svhost-ssl.conf <<EOF # Generated by: ssl-start $* @@ -188,6 +160,49 @@ AliasMatch /v/([^/]+)(.*)$ $here/htdocs/app\$2 EOF +# Configure admin access to server status and info +cat >tmp/conf/adminauth.conf <<EOF +# Generated by: ssl-start $* +# Allow the server admin to view the server status and info +<Location /server-status> +AuthType None +Require all granted +</Location> + +<Location /server-info> +AuthType None +Require all granted +</Location> + +EOF + +# Configure admin access to components +cat >>tmp/conf/locauth-ssl.conf <<EOF +# Generated by: ssl-start $* +# Allow the server admin to access all components +<Location /c> +Require user admin +</Location> +<Location /r> +Require user admin +</Location> +<Location /r/Editor> +Require valid-user +</Location> +<Location /r/App> +Require valid-user +</Location> +EOF + # Start server ../../modules/http/httpd-start tmp +sleep 2 + +# Configure authorized users +./put-auth tmp admin admin admin admin +./put-auth tmp admin admin john john +./put-auth tmp admin admin jane jane +# Configure the email addresses associated with your OAuth ids here +./put-auth tmp admin admin /oauth1/john@example.com password +./put-auth tmp admin admin /oauth2/jane@example.com password diff --git a/sca-cpp/trunk/hosting/server/user.py b/sca-cpp/trunk/hosting/server/user.py index 9be48b33da..8038e43563 100644 --- a/sca-cpp/trunk/hosting/server/user.py +++ b/sca-cpp/trunk/hosting/server/user.py @@ -21,9 +21,7 @@ def get(i, user, email, nick, full, first, last, realm, host): if email.eval() != '?': return email.eval() - if nick.eval() != '?': - return nick.eval() + '@' + realm.eval() if user.eval() != '?': - return user.eval() + '@' + realm.eval() - return 'anonymous@' + host.eval(); + return user.eval() + return 'anonymous' diff --git a/sca-cpp/trunk/modules/http/basic-auth-conf b/sca-cpp/trunk/modules/http/basic-auth-conf index 39dde90b50..8710d1fdf7 100755 --- a/sca-cpp/trunk/modules/http/basic-auth-conf +++ b/sca-cpp/trunk/modules/http/basic-auth-conf @@ -25,9 +25,16 @@ root=`echo "import os; print os.path.realpath('$1')" | python` conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` host=`echo $conf | awk '{ print $6 }'` -loc=$2 -if [ "$loc" = "" ]; then +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then loc="/" +else + loc="$3" fi sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` @@ -52,7 +59,9 @@ cat >>$root/conf/locauth$sslsuffix.conf <<EOF <Location $loc> AuthType Basic AuthName "$host" -AuthBasicProvider file +AuthBasicProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / Require valid-user </Location> diff --git a/sca-cpp/trunk/modules/http/cert-auth-conf b/sca-cpp/trunk/modules/http/cert-auth-conf index 514e46324f..a30fdfff8c 100755 --- a/sca-cpp/trunk/modules/http/cert-auth-conf +++ b/sca-cpp/trunk/modules/http/cert-auth-conf @@ -32,6 +32,12 @@ else sslsuffix="-ssl" fi +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + # Disallow public access to server resources cat >$root/conf/noauth$sslsuffix.conf <<EOF # Generated by: cert-auth-conf $* @@ -49,7 +55,9 @@ SSLVerifyDepth 1 <Location /> AuthType Basic AuthName "$host" -AuthBasicProvider file +AuthBasicProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / Require valid-user </Location> diff --git a/sca-cpp/trunk/modules/http/form-auth-conf b/sca-cpp/trunk/modules/http/form-auth-conf index 08b97b9df8..fbe943f3d9 100755 --- a/sca-cpp/trunk/modules/http/form-auth-conf +++ b/sca-cpp/trunk/modules/http/form-auth-conf @@ -26,9 +26,15 @@ conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` host=`echo $conf | awk '{ print $6 }'` if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then pw=`cat $root/cert/ca.key | head -2 | tail -1` else - pw="$2" + pw="$3" fi sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` @@ -53,8 +59,10 @@ cat >>$root/conf/locauth$sslsuffix.conf <<EOF <Location /> AuthType Form AuthName "$host" -AuthFormProvider file -AuthFormLoginRequiredLocation /login +AuthFormProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +AuthFormLoginRequiredLocation /login/ AuthFormLogoutLocation / Session On SessionCookieName TuscanyFormAuth domain=.$host; path=/ diff --git a/sca-cpp/trunk/modules/http/httpd-ssl-conf b/sca-cpp/trunk/modules/http/httpd-ssl-conf index 3cb90d61e0..f99a10071c 100755 --- a/sca-cpp/trunk/modules/http/httpd-ssl-conf +++ b/sca-cpp/trunk/modules/http/httpd-ssl-conf @@ -43,6 +43,15 @@ htdocs=`echo $conf | awk '{ print $8 }'` mkdir -p $htdocs htdocs=`echo "import os; print os.path.realpath('$htdocs')" | python` +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +modules_prefix=`cat $here/httpd-modules.prefix` + # Extract organization name from our CA certificate org=`openssl x509 -noout -subject -nameopt multiline -in $root/cert/ca.crt | grep organizationName | awk -F "= " '{ print $2 }'` @@ -69,7 +78,7 @@ ServerName https://$host$sslpportsuffix <Location /> RewriteEngine on -RewriteCond %{HTTP_HOST} !^$host [NC] +Include conf/hostcond.conf RewriteCond %{HTTP:X-Forwarded-Server} ^$ [NC] RewriteCond %{REQUEST_URI} !^/server-status [NC] RewriteCond %{REQUEST_URI} !^/balancer-manager [NC] @@ -176,7 +185,7 @@ Include conf/log-ssl.conf # Enable HTTPS reverse proxy ProxyRequests Off -ProxyPreserveHost Off +ProxyPreserveHost On ProxyStatus On SSLProxyEngine on SSLProxyCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL @@ -222,11 +231,6 @@ CustomLog $root/logs/ssl_access_log sslcombined EOF # Configure virtual hosts -proxycert="server" -if [ "$proxyconf" != "" ]; then - proxycert="proxy" -fi - cat >$root/conf/svhost-ssl.conf <<EOF # Generated by: httpd-ssl-conf $* # Static virtual host configuration @@ -238,10 +242,6 @@ SSLCertificateChainFile "$root/cert/ca.crt" SSLCertificateFile "$root/cert/server.crt" SSLCertificateKeyFile "$root/cert/server.key" -# Declare proxy SSL client certificates -SSLProxyCACertificateFile "$root/cert/ca.crt" -SSLProxyMachineCertificateFile "$root/cert/$proxycert.pem" - EOF cat >$root/conf/dvhost-ssl.conf <<EOF @@ -255,9 +255,5 @@ SSLCertificateChainFile "$root/cert/ca.crt" SSLCertificateFile "$root/cert/vhost.crt" SSLCertificateKeyFile "$root/cert/vhost.key" -# Declare proxy SSL client certificates -SSLProxyCACertificateFile "$root/cert/ca.crt" -SSLProxyMachineCertificateFile "$root/cert/$proxycert.pem" - EOF diff --git a/sca-cpp/trunk/modules/http/httpd-tunnel-ssl-conf b/sca-cpp/trunk/modules/http/httpd-tunnel-ssl-conf new file mode 100755 index 0000000000..0028576364 --- /dev/null +++ b/sca-cpp/trunk/modules/http/httpd-tunnel-ssl-conf @@ -0,0 +1,38 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Generate a minimal HTTPD SSL Tunnel configuration +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +# Generate required modules list +cat >>$root/conf/modules.conf <<EOF +# Generated by: httpd-tunnel-ssl-conf $* +LoadModule mod_tuscany_ssltunnel $here/libmod_tuscany_ssltunnel$libsuffix + +EOF + diff --git a/sca-cpp/trunk/modules/http/mod-openauth.cpp b/sca-cpp/trunk/modules/http/mod-openauth.cpp index b1aabd73fe..2e308ecedb 100644 --- a/sca-cpp/trunk/modules/http/mod-openauth.cpp +++ b/sca-cpp/trunk/modules/http/mod-openauth.cpp @@ -44,6 +44,7 @@ #include "http.hpp" #include "openauth.hpp" + extern "C" { extern module AP_MODULE_DECLARE_DATA mod_tuscany_openauth; } @@ -64,6 +65,20 @@ public: }; /** + * Authentication provider configuration. + */ +class AuthnProviderConf { +public: + AuthnProviderConf() : name(), provider(NULL) { + } + AuthnProviderConf(const string name, const authn_provider* provider) : name(name), provider(provider) { + } + + string name; + const authn_provider* provider; +}; + +/** * Directory configuration. */ class DirConf { @@ -75,6 +90,7 @@ public: const char* dir; bool enabled; string login; + list<AuthnProviderConf> apcs; }; #ifdef WANT_MAINTAINER_LOG @@ -101,10 +117,39 @@ const bool debugSession(request_rec* r, session_rec* z) { #endif /** + * Run the authnz hooks to authenticate a request. + */ +const failable<int> checkAuthnzProviders(const string& user, const string& pw, request_rec* r, const list<AuthnProviderConf>& apcs) { + if (isNil(apcs)) + return mkfailure<int>("Authentication failure for: " + user); + const AuthnProviderConf apc = car<AuthnProviderConf>(apcs); + if (apc.provider == NULL || !apc.provider->check_password) + return checkAuthnzProviders(user, pw, r, cdr(apcs)); + + apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, c_str(apc.name)); + const authn_status auth_result = apc.provider->check_password(r, c_str(user), c_str(pw)); + apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); + if (auth_result != AUTH_GRANTED) + return checkAuthnzProviders(user, pw, r, cdr(apcs)); + return OK; +} + +const failable<int> checkAuthnz(const string& user, const string& pw, request_rec* r, const DirConf& dc) { + if (substr(user, 0, 1) == "/" && pw == "password") + return mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED); + + if (isNil(dc.apcs)) { + const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION); + return checkAuthnzProviders(user, pw, r, mklist<AuthnProviderConf>(AuthnProviderConf(AUTHN_DEFAULT_PROVIDER, provider))); + } + return checkAuthnzProviders(user, pw, r, dc.apcs); +} + +/** * Return the user info from a form auth encrypted session cookie. */ static int (*ap_session_load_fn) (request_rec * r, session_rec ** z) = NULL; -static void (*ap_session_get_fn) (request_rec * r, session_rec * z, const char *key, const char **value) = NULL; +static int (*ap_session_get_fn) (request_rec * r, session_rec * z, const char *key, const char **value) = NULL; const failable<value> userInfoFromSession(const string& realm, request_rec* r) { debug("modopenauth::userInfoFromSession"); @@ -186,36 +231,23 @@ const failable<int> authenticated(const list<list<value> >& info, request_rec* r } /** - * Run the authnz hooks to try to authenticate a request. - */ -const failable<int> checkAuthnz(const string& user, const string& pw, request_rec* r) { - const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION); - if (!provider || !provider->check_password) - return mkfailure<int>("No Authn provider configured"); - apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER); - const authn_status auth_result = provider->check_password(r, c_str(user), c_str(pw)); - apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); - if (auth_result != AUTH_GRANTED) - return mkfailure<int>("Authentication failure for: " + user); - return OK; -} - -/** * Check user authentication. */ static int checkAuthn(request_rec *r) { + gc_scoped_pool pool(r->pool); + // Decline if we're not enabled or AuthType is not set to Open const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth); if (!dc.enabled) return DECLINED; const char* atype = ap_auth_type(r); - debug(atype, "modopenauth::checkAuthn::auth_type"); if (atype == NULL || strcasecmp(atype, "Open")) return DECLINED; - - // Create a scoped memory pool - gc_scoped_pool pool(r->pool); debug_httpdRequest(r, "modopenauth::checkAuthn::input"); + debug(atype, "modopenauth::checkAuthn::auth_type"); + + // Get the request args + const list<list<value> > args = httpd::queryArgs(r); // Get session id from the request const maybe<string> sid = sessionID(r, "TuscanyOpenAuth"); @@ -231,17 +263,17 @@ static int checkAuthn(request_rec *r) { return httpd::reportStatus(mkfailure<int>("Missing AuthName")); // Extract user info from the session id - const failable<value> info = userInfoFromCookie(content(sid), aname, r); - if (hasContent(info)) { + const failable<value> userinfo = userInfoFromCookie(content(sid), aname, r); + if (hasContent(userinfo)) { // Try to authenticate the request - const value uinfo = content(info); - const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r); + const value uinfo = content(userinfo); + const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r, dc); if (!hasContent(authz)) { // Authentication failed, redirect to login page r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(login(dc.login, r)); + return httpd::reportStatus(login(dc.login, value(), 1, r)); } // Successfully authenticated, store the user info in the request @@ -265,12 +297,12 @@ static int checkAuthn(request_rec *r) { // Try to authenticate the request const value uinfo = content(info); - const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r); + const failable<int> authz = checkAuthnz(cadr(assoc<value>("id", uinfo)), cadr(assoc<value>("password", uinfo)), r, dc); if (!hasContent(authz)) { // Authentication failed, redirect to login page r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(login(dc.login, r)); + return httpd::reportStatus(login(dc.login, value(), 1, r)); } // Successfully authenticated, store the user info in the request @@ -279,9 +311,6 @@ static int checkAuthn(request_rec *r) { } } - // Get the request args - const list<list<value> > args = httpd::queryArgs(r); - // Decline if the request is for another authentication provider if (!isNil(assoc<value>("openid_identifier", args))) return DECLINED; @@ -291,57 +320,59 @@ static int checkAuthn(request_rec *r) { hasContent(sessionID(r, "TuscanyOAuth1")) || hasContent(sessionID(r, "TuscanyOAuth2"))) return DECLINED; + r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(login(dc.login, r)); + return httpd::reportStatus(login(dc.login, value(), value(), r)); } /** - * Fixup cache control. + * Save the auth session cookie in the response. */ -bool filterCacheControl(const string& tok) { - return tok != "no-cache"; +static int sessionCookieSave(request_rec* r, session_rec* z) { + gc_scoped_pool pool(r->pool); + + const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth); + if (!dc.enabled) + return DECLINED; + + debug(c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r))), "modopenauth::setcookie"); + apr_table_set(r->err_headers_out, "Set-Cookie", c_str(cookie("TuscanyOpenAuth", z->encoded, httpd::hostName(r)))); + return OK; } -static apr_status_t outputFilter(ap_filter_t * f, apr_bucket_brigade * in) { - request_rec *r = f->r->main; - if (!r) - r = f->r; - for (; r != NULL; r = r->next) { - if (r->status != HTTP_OK && r->status != HTTP_NOT_MODIFIED) { - - // Don't cache errors and redirects - debug("no-cache", "modopenauth::outputFilter::nokCacheControl"); - apr_table_set(r->headers_out, "Cache-Control", "no-cache"); - continue; - } +/** + * Load the auth session cookie from the request. Similar + */ +static int sessionCookieLoad(request_rec* r, session_rec** z) { + gc_scoped_pool pool(r->pool); - // Cache OK content - const char* cc = apr_table_get(r->headers_out, "Cache-Control"); - if (cc == NULL) { - debug("modopenauth::outputFilter::noCacheControl"); - continue; - } - debug(cc, "modopenauth::outputFilter::cacheControl"); - const string ncc = join(", ", filter<string>(filterCacheControl, tokenize(", ", cc))); - if (length(ncc) == 0) { - debug("modopenauth::outputFilter::noCacheControl"); - apr_table_unset(r->headers_out, "Cache-Control"); - continue; - } + const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_openauth); + if (!dc.enabled) + return DECLINED; - debug(ncc, "modopenauth::outputFilter::okCacheControl"); - apr_table_set(r->headers_out, "Cache-Control", c_str(ncc)); + // First look in the notes + const char* note = apr_pstrcat(r->pool, "mod_openauth", "TuscanyOpenAuth", NULL); + session_rec* zz = (session_rec*)(void*)apr_table_get(r->notes, note); + if (zz != NULL) { + *z = zz; + return OK; } - ap_remove_output_filter(f); - return ap_pass_brigade(f->next, in); -} + // Parse the cookie + const maybe<string> sid = openauth::sessionID(r, "TuscanyOpenAuth"); -/** - * Insert our cache control output filter. - */ -static void insertOutputFilter(request_rec * r) { - ap_add_output_filter("mod_openauth", NULL, r, r->connection); + // Create a new session + zz = (session_rec*)apr_pcalloc(r->pool, sizeof(session_rec)); + zz->pool = r->pool; + zz->entries = apr_table_make(r->pool, 10); + zz->encoded = hasContent(sid)? c_str(content(sid)) : NULL; + zz->uuid = (apr_uuid_t *) apr_pcalloc(r->pool, sizeof(apr_uuid_t)); + *z = zz; + + // Store it in the notes + apr_table_setn(r->notes, note, (char*)zz); + + return OK; } /** @@ -357,6 +388,7 @@ int postConfigMerge(ServerConf& mainsc, server_rec* s) { int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) { gc_scoped_pool pool(p); + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_openauth); debug(httpd::serverName(s), "modopenauth::postConfig::serverName"); @@ -369,6 +401,7 @@ int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, */ void childInit(apr_pool_t* p, server_rec* s) { gc_scoped_pool pool(p); + ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_openauth); if(psc == NULL) { cfailure << "[Tuscany] Due to one or more errors mod_tuscany_openauth loading failed. Causing apache to stop loading." << endl; @@ -395,11 +428,25 @@ const char* confLogin(cmd_parms *cmd, void *c, const char* arg) { dc.login = arg; return NULL; } +const char* confAuthnProvider(cmd_parms *cmd, void *c, const char* arg) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf<DirConf>(c); + + // Lookup and cache the Authn provider + const authn_provider* provider = (authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, arg, AUTHN_PROVIDER_VERSION); + if (provider == NULL) + return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", arg); + if (!provider->check_password) + return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support password authentication", arg); + dc.apcs = append<AuthnProviderConf>(dc.apcs, mklist<AuthnProviderConf>(AuthnProviderConf(arg, provider))); + return NULL; +} /** * HTTP server module declaration. */ const command_rec commands[] = { + AP_INIT_ITERATE("AuthOpenAuthProvider", (const char*(*)())confAuthnProvider, NULL, OR_AUTHCFG, "Auth providers for a directory or location"), AP_INIT_FLAG("AuthOpenAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "Tuscany Open Auth authentication On | Off"), AP_INIT_TAKE1("AuthOpenAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "Tuscany Open Auth login page"), {NULL, NULL, NULL, 0, NO_ARGS, NULL} @@ -409,8 +456,8 @@ void registerHooks(unused apr_pool_t *p) { ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_check_authn(checkAuthn, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF); - ap_register_output_filter("mod_openauth", outputFilter, NULL, AP_FTYPE_CONTENT_SET); - ap_hook_insert_filter(insertOutputFilter, NULL, NULL, APR_HOOK_LAST); + ap_hook_session_load(sessionCookieLoad, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_session_save(sessionCookieSave, NULL, NULL, APR_HOOK_MIDDLE); } } diff --git a/sca-cpp/trunk/modules/http/mod-security-conf b/sca-cpp/trunk/modules/http/mod-security-conf index 4d978a01cb..5d03fc5cfb 100755 --- a/sca-cpp/trunk/modules/http/mod-security-conf +++ b/sca-cpp/trunk/modules/http/mod-security-conf @@ -51,8 +51,8 @@ SecDefaultAction "phase:2,pass,nolog,auditlog" #SecDebugLog $root/logs//modsec_debug_log #SecDebugLogLevel 3 -# Allow mod-security to access request bodies -SecRequestBodyAccess On +# Process request bodies +SecRequestBodyAccess Off SecRule REQUEST_HEADERS:Content-Type "text/xml" "phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" SecRule REQUEST_HEADERS:Content-Type "application/xml" "phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" SecRequestBodyLimit 13107200 @@ -90,8 +90,8 @@ SecRule RESPONSE_STATUS "@streq 408" "phase:5,t:none,nolog,pass, setvar:ip.slow_ SecRule IP:SLOW_DOS_COUNTER "@gt 5" "phase:1,t:none,log,drop, msg:'Client Connection Dropped due to high # of slow DoS alerts'" SecWriteStateLimit 50 -# Allow mod-security to access response bodies -SecResponseBodyAccess On +# Process response bodies +SecResponseBodyAccess Off SecResponseBodyMimeType text/plain text/html text/xml application/xml SecResponseBodyLimit 524288 SecResponseBodyLimitAction ProcessPartial @@ -157,28 +157,28 @@ SecRule &TX:REAL_IP "@eq 0" "phase:1,id:'981218',t:none,pass,nolog,initcol:glob # Include all base mod-security CRS rules Include ${modsecurity_prefix}/base_rules/modsecurity_crs_20_protocol_violations.conf -Include ${modsecurity_prefix}/base_rules/modsecurity_crs_41_xss_attacks.conf -Include ${modsecurity_prefix}/base_rules/modsecurity_crs_50_outbound.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_41_xss_attacks.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_50_outbound.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_35_bad_robots.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_47_common_exceptions.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_60_correlation.conf -Include ${modsecurity_prefix}/base_rules/modsecurity_crs_40_generic_attacks.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_40_generic_attacks.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_21_protocol_anomalies.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_30_http_policy.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_49_inbound_blocking.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_41_sql_injection_attacks.conf -Include ${modsecurity_prefix}/base_rules/modsecurity_crs_45_trojans.conf +#Include ${modsecurity_prefix}/base_rules/modsecurity_crs_45_trojans.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_59_outbound_blocking.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_23_request_limits.conf Include ${modsecurity_prefix}/base_rules/modsecurity_crs_42_tight_security.conf # Include some optional mod-security CRS rules -Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_10_ignore_static.conf -Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_13_xml_enabler.conf -Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_25_cc_known.conf -Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_42_comment_spam.conf -Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_47_skip_outbound_checks.conf -Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_55_application_defects.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_10_ignore_static.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_13_xml_enabler.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_25_cc_known.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_42_comment_spam.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_47_skip_outbound_checks.conf +#Include ${modsecurity_prefix}/optional_rules/modsecurity_crs_55_application_defects.conf EOF diff --git a/sca-cpp/trunk/modules/http/open-auth-conf b/sca-cpp/trunk/modules/http/open-auth-conf index 5226622058..f4715b3a1c 100755 --- a/sca-cpp/trunk/modules/http/open-auth-conf +++ b/sca-cpp/trunk/modules/http/open-auth-conf @@ -40,14 +40,20 @@ else fi if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +if [ "$3" = "" ]; then pw=`cat $root/cert/ca.key | head -2 | tail -1` else - pw="$2" + pw="$3" fi # Configure HTTPD mod_tuscany_openauth module cat >>$root/conf/modules.conf <<EOF -# Generated by: openauth-conf $* +# Generated by: open-auth-conf $* # Load support for Open authentication LoadModule mod_tuscany_openauth $here/libmod_tuscany_openauth$libsuffix @@ -67,11 +73,13 @@ cat >>$root/conf/locauth$sslsuffix.conf <<EOF <Location /> AuthType Open AuthName "$host" +AuthOpenAuthProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / Session On -SessionCookieName TuscanyOpenAuth domain=.$host; path=/ SessionCryptoPassphrase $pw AuthOpenAuth On -AuthOpenAuthLoginPage /login +AuthOpenAuthLoginPage /login/ Require valid-user </Location> @@ -79,8 +87,10 @@ Require valid-user <Location /login/dologin> AuthType Form AuthName "$host" -AuthFormProvider file -AuthFormLoginRequiredLocation /login +AuthFormProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +AuthFormLoginRequiredLocation /login/?openauth_attempt=1 AuthFormLogoutLocation / Require valid-user SetHandler form-login-handler diff --git a/sca-cpp/trunk/modules/http/openauth.hpp b/sca-cpp/trunk/modules/http/openauth.hpp index 5d887885aa..3ffa88d362 100644 --- a/sca-cpp/trunk/modules/http/openauth.hpp +++ b/sca-cpp/trunk/modules/http/openauth.hpp @@ -77,7 +77,7 @@ const string cookie(const string& key, const string& sid, const string& domain) 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 = key + string("=") + sid + "; expires=" + string(exp) + "; domain=." + domain + "; path=/"; + const string c = key + string("=") + sid + "; expires=" + string(exp) + "; domain=." + httpd::realm(domain) + "; path=/"; debug(c, "openauth::cookie"); return c; } @@ -85,9 +85,11 @@ const string cookie(const string& key, const string& sid, const string& domain) /** * Redirect to the configured login page. */ -const failable<int> login(const string& page, request_rec* r) { - const list<list<value> > largs = mklist<list<value> >(mklist<value>("openauth_referrer", httpd::escape(httpd::url(r->uri, r)))); - const string loc = httpd::url(page, r) + string("?") + http::queryString(largs); +const failable<int> login(const string& page, const value& ref, const value& attempt, request_rec* r) { + const list<list<value> > rarg = ref == string("/")? list<list<value> >() : mklist<list<value> >(mklist<value>("openauth_referrer", httpd::escape(httpd::url(isNil(ref)? r->uri : ref, r)))); + const list<list<value> > aarg = isNil(attempt)? list<list<value> >() : mklist<list<value> >(mklist<value>("openauth_attempt", attempt)); + const list<list<value> > largs = append<list<value> >(rarg, aarg); + const string loc = isNil(largs)? httpd::url(page, r) : httpd::url(page, r) + string("?") + http::queryString(largs); debug(loc, "openauth::login::uri"); return httpd::externalRedirect(loc, r); } diff --git a/sca-cpp/trunk/modules/http/passwd-auth-conf b/sca-cpp/trunk/modules/http/passwd-auth-conf index 119b0fbb3b..718b96de0a 100755 --- a/sca-cpp/trunk/modules/http/passwd-auth-conf +++ b/sca-cpp/trunk/modules/http/passwd-auth-conf @@ -27,5 +27,5 @@ httpd_prefix=`cat $here/httpd.prefix` # Create password file touch $root/conf/httpd.passwd -$httpd_prefix/bin/htpasswd -b $root/conf/httpd.passwd $user $pass 2>/dev/null +$httpd_prefix/bin/htpasswd -b $root/conf/httpd.passwd "$user" "$pass" 2>/dev/null diff --git a/sca-cpp/trunk/modules/oauth/Makefile.am b/sca-cpp/trunk/modules/oauth/Makefile.am index a5a5916a84..9e8eb5a0dd 100644 --- a/sca-cpp/trunk/modules/oauth/Makefile.am +++ b/sca-cpp/trunk/modules/oauth/Makefile.am @@ -19,7 +19,7 @@ if WANT_OAUTH INCLUDES = -I${HTTPD_INCLUDE} -I${LIBOAUTH_INCLUDE} -dist_mod_SCRIPTS = oauth-conf oauth-memcached-conf oauth1-appkey-conf oauth2-appkey-conf +dist_mod_SCRIPTS = oauth-conf oauth12-conf oauth-memcached-conf oauth1-appkey-conf oauth2-appkey-conf moddir=$(prefix)/modules/oauth mod_LTLIBRARIES = libmod_tuscany_oauth1.la libmod_tuscany_oauth2.la diff --git a/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp b/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp index eb23443491..d2c7cf7ddd 100644 --- a/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp +++ b/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp @@ -71,6 +71,20 @@ public: }; /** + * Authentication provider configuration. + */ +class AuthnProviderConf { +public: + AuthnProviderConf() : name(), provider(NULL) { + } + AuthnProviderConf(const string name, const authn_provider* provider) : name(name), provider(provider) { + } + + string name; + const authn_provider* provider; +}; + +/** * Directory configuration. */ class DirConf { @@ -83,9 +97,39 @@ public: bool enabled; string login; list<list<value> > scopeattrs; + list<AuthnProviderConf> apcs; }; /** + * Run the authnz hooks to authenticate a request. + */ +const failable<int> checkAuthnzProviders(const string& user, request_rec* r, const list<AuthnProviderConf>& apcs) { + if (isNil(apcs)) + return mkfailure<int>("Authentication failure for: " + user, HTTP_UNAUTHORIZED); + const AuthnProviderConf apc = car<AuthnProviderConf>(apcs); + if (apc.provider == NULL || !apc.provider->check_password) + return checkAuthnzProviders(user, r, cdr(apcs)); + + apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, c_str(apc.name)); + const authn_status auth_result = apc.provider->check_password(r, c_str(string("/oauth1/") + user), "password"); + apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); + if (auth_result != AUTH_GRANTED) + return checkAuthnzProviders(user, r, cdr(apcs)); + return OK; +} + +const failable<int> checkAuthnz(const string& user, request_rec* r, const list<AuthnProviderConf>& apcs) { + if (substr(user, 0, 1) == "/") + return mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED); + + if (isNil(apcs)) { + const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION); + return checkAuthnzProviders(user, r, mklist<AuthnProviderConf>(AuthnProviderConf(AUTHN_DEFAULT_PROVIDER, provider))); + } + return checkAuthnzProviders(user, r, apcs); +} + +/** * Return the user info for a session. */ const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) { @@ -95,27 +139,31 @@ const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) /** * Handle an authenticated request. */ -const failable<int> authenticated(const list<list<value> >& attrs, const list<list<value> >& info, request_rec* r) { - debug(info, "modoauth1::authenticated::info"); +const failable<int> authenticated(const list<list<value> >& userinfo, const bool check, request_rec* r, const list<list<value> >& scopeattrs, const list<AuthnProviderConf>& apcs) { + debug(userinfo, "modoauth2::authenticated::userinfo"); - if (isNil(attrs)) { + if (isNil(scopeattrs)) { // Store user id in an environment variable - const list<value> id = assoc<value>("id", info); + const list<value> id = assoc<value>("id", userinfo); if (isNil(id) || isNil(cdr(id))) return mkfailure<int>("Couldn't retrieve user id"); - apr_table_set(r->subprocess_env, "OAUTH1_ID", apr_pstrdup(r->pool, c_str(cadr(id)))); + apr_table_set(r->subprocess_env, "OAUTH2_ID", apr_pstrdup(r->pool, c_str(cadr(id)))); // If the request user field has not been mapped to another attribute, map the // OAuth id attribute to it if (r->user == NULL || r->user[0] == '\0') r->user = apr_pstrdup(r->pool, c_str(cadr(id))); + + // Run the authnz hooks to check the authenticated user + if (check) + return checkAuthnz(r->user == NULL? "" : r->user, r, apcs); return OK; } - // Store each configure OAuth scope attribute in an environment variable - const list<value> a = car(attrs); - const list<value> v = assoc<value>(cadr(a), info); + // Store each configured OAuth scope attribute in an environment variable + const list<value> a = car(scopeattrs); + const list<value> v = assoc<value>(cadr(a), userinfo); if (!isNil(v) && !isNil(cdr(v))) { // Map the REMOTE_USER attribute to the request user field @@ -124,7 +172,7 @@ const failable<int> authenticated(const list<list<value> >& attrs, const list<li else apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, c_str(car(a))), apr_pstrdup(r->pool, c_str(cadr(v)))); } - return authenticated(cdr(attrs), info, r); + return authenticated(userinfo, check, r, cdr(scopeattrs), apcs); } /** @@ -297,7 +345,8 @@ const failable<list<value> > profileUserInfo(const value& cid, const string& inf /** * Handle an access_token request. */ -const failable<int> accessToken(const list<list<value> >& args, request_rec* r, const list<list<value> >& appkeys, const memcache::MemCached& mc) { +const failable<int> accessToken(const list<list<value> >& args, request_rec* r, const list<list<value> >& appkeys, const list<list<value> >& scopeattrs, const list<AuthnProviderConf>& apcs, const memcache::MemCached& mc) { + // Extract access_token URI, client ID and verification code const list<value> ref = assoc<value>("openauth_referrer", args); if (isNil(ref) || isNil(cdr(ref))) @@ -372,13 +421,18 @@ const failable<int> accessToken(const list<list<value> >& args, request_rec* r, debug(profres, "modoauth1::access_token::profres"); // Retrieve the user info from the profile - const failable<list<value> > iv = profileUserInfo(cadr(cid), profres); - if (!hasContent(iv)) - return mkfailure<int>(iv); + const failable<list<value> > userinfo = profileUserInfo(cadr(cid), profres); + if (!hasContent(userinfo)) + return mkfailure<int>(userinfo); + + // Validate the authenticated user + const failable<int> authrc = authenticated(content(userinfo), true, r, scopeattrs, apcs); + if (!hasContent(authrc)) + return authrc; // Store user info in memcached keyed by session ID const value sid = string("OAuth1_") + mkrand(); - const failable<bool> prc = memcache::put(mklist<value>("tuscanyOAuth1", sid), content(iv), mc); + const failable<bool> prc = memcache::put(mklist<value>("tuscanyOAuth1", sid), content(userinfo), mc); if (!hasContent(prc)) return mkfailure<int>(prc); @@ -392,20 +446,19 @@ const failable<int> accessToken(const list<list<value> >& args, request_rec* r, * Check user authentication. */ static int checkAuthn(request_rec *r) { + gc_scoped_pool pool(r->pool); + // Decline if we're not enabled or AuthType is not set to Open const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth1); if (!dc.enabled) return DECLINED; const char* atype = ap_auth_type(r); - debug(atype, "modopenauth::checkAuthn::auth_type"); if (atype == NULL || strcasecmp(atype, "Open")) return DECLINED; - - // Create a scoped memory pool - gc_scoped_pool pool(r->pool); + debug_httpdRequest(r, "modoauth1::checkAuthn::input"); + debug(atype, "modopenauth::checkAuthn::auth_type"); // Get the server configuration - debug_httpdRequest(r, "modoauth1::checkAuthn::input"); const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth1); // Get session id from the request @@ -415,24 +468,33 @@ static int checkAuthn(request_rec *r) { if (substr(content(sid), 0, 7) != "OAuth1_") return DECLINED; - // If we're authenticated store the user info in the request - const failable<value> info = userInfo(content(sid), sc.mc); - if (hasContent(info)) { - r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(authenticated(dc.scopeattrs, content(info), r)); - } + // Extract the user info from the auth session + const failable<value> userinfo = userInfo(content(sid), sc.mc); + if (!hasContent(userinfo)) + return httpd::reportStatus(mkfailure<int>(userinfo)); + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(authenticated(content(userinfo), false, r, dc.scopeattrs, dc.apcs)); } + // Get the request args + const list<list<value> > args = httpd::queryArgs(r); + // Handle OAuth authorize request step if (string(r->uri) == "/oauth1/authorize/") { r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(authorize(httpd::queryArgs(r), r, sc.appkeys, sc.mc)); + return httpd::reportStatus(authorize(args, r, sc.appkeys, sc.mc)); } // Handle OAuth access_token request step if (string(r->uri) == "/oauth1/access_token/") { r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(accessToken(httpd::queryArgs(r), r, sc.appkeys, sc.mc)); + const failable<int> authrc = accessToken(args, r, sc.appkeys, dc.scopeattrs, dc.apcs, sc.mc); + + // Redirect to the login page if user is not authorized + if (!hasContent(authrc) && rcode(authrc) == HTTP_UNAUTHORIZED) + return httpd::reportStatus(openauth::login(dc.login, string("/"), 1, r)); + + return httpd::reportStatus(authrc); } // Redirect to the login page, unless we have a session id or an authorization @@ -443,10 +505,11 @@ static int checkAuthn(request_rec *r) { hasContent(openauth::sessionID(r, "TuscanyOpenAuth")) || hasContent(openauth::sessionID(r, "TuscanyOAuth2"))) return DECLINED; - if ((substr(string(r->uri), 0, 8) == "/oauth2/") || !isNil(assoc<value>("openid_identifier", httpd::queryArgs(r)))) + if ((substr(string(r->uri), 0, 8) == "/oauth2/") || !isNil(assoc<value>("openid_identifier", args))) return DECLINED; + r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(openauth::login(dc.login, r)); + return httpd::reportStatus(openauth::login(dc.login, value(), value(), r)); } /** @@ -471,6 +534,7 @@ int postConfigMerge(ServerConf& mainsc, server_rec* s) { int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) { gc_scoped_pool pool(p); + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth1); debug(httpd::serverName(s), "modoauth1::postConfig::serverName"); @@ -487,7 +551,7 @@ public: } const gc_ptr<http::CURLSession> operator()() const { - return new (gc_new<http::CURLSession>()) http::CURLSession(ca, cert, key, ""); + return new (gc_new<http::CURLSession>()) http::CURLSession(ca, cert, key, "", 0); } private: @@ -501,6 +565,7 @@ private: */ void childInit(apr_pool_t* p, server_rec* s) { gc_scoped_pool pool(p); + ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_oauth1); if(psc == NULL) { cfailure << "[Tuscany] Due to one or more errors mod_tuscany_oauth1 loading failed. Causing apache to stop loading." << endl; @@ -572,11 +637,25 @@ const char* confScopeAttr(cmd_parms *cmd, void* c, const char* arg1, const char* dc.scopeattrs = cons<list<value> >(mklist<value>(arg1, arg2), dc.scopeattrs); return NULL; } +const char* confAuthnProvider(cmd_parms *cmd, void *c, const char* arg) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf<DirConf>(c); + + // Lookup and cache the Authn provider + const authn_provider* provider = (authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, arg, AUTHN_PROVIDER_VERSION); + if (provider == NULL) + return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", arg); + if (!provider->check_password) + return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support password authentication", arg); + dc.apcs = append<AuthnProviderConf>(dc.apcs, mklist<AuthnProviderConf>(AuthnProviderConf(arg, provider))); + return NULL; +} /** * HTTP server module declaration. */ const command_rec commands[] = { + AP_INIT_ITERATE("AuthOAuthProvider", (const char*(*)())confAuthnProvider, NULL, OR_AUTHCFG, "Auth providers for a directory or location"), AP_INIT_TAKE3("AddAuthOAuth1AppKey", (const char*(*)())confAppKey, NULL, RSRC_CONF, "OAuth 1.0 name app-id app-key"), AP_INIT_ITERATE("AddAuthOAuthMemcached", (const char*(*)())confMemcached, NULL, RSRC_CONF, "Memcached server host:port"), AP_INIT_FLAG("AuthOAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "OAuth 1.0 authentication On | Off"), diff --git a/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp b/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp index cbece191aa..e384a0e742 100644 --- a/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp +++ b/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp @@ -65,6 +65,20 @@ public: }; /** + * Authentication provider configuration. + */ +class AuthnProviderConf { +public: + AuthnProviderConf() : name(), provider(NULL) { + } + AuthnProviderConf(const string name, const authn_provider* provider) : name(name), provider(provider) { + } + + string name; + const authn_provider* provider; +}; + +/** * Directory configuration. */ class DirConf { @@ -77,9 +91,39 @@ public: bool enabled; string login; list<list<value> > scopeattrs; + list<AuthnProviderConf> apcs; }; /** + * Run the authnz hooks to authenticate a request. + */ +const failable<int> checkAuthnzProviders(const string& user, request_rec* r, const list<AuthnProviderConf>& apcs) { + if (isNil(apcs)) + return mkfailure<int>("Authentication failure for: " + user, HTTP_UNAUTHORIZED); + const AuthnProviderConf apc = car<AuthnProviderConf>(apcs); + if (apc.provider == NULL || !apc.provider->check_password) + return checkAuthnzProviders(user, r, cdr(apcs)); + + apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, c_str(apc.name)); + const authn_status auth_result = apc.provider->check_password(r, c_str(string("/oauth2/") + user), "password"); + apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); + if (auth_result != AUTH_GRANTED) + return checkAuthnzProviders(user, r, cdr(apcs)); + return OK; +} + +const failable<int> checkAuthnz(const string& user, request_rec* r, const list<AuthnProviderConf>& apcs) { + if (substr(user, 0, 1) == "/") + return mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED); + + if (isNil(apcs)) { + const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION); + return checkAuthnzProviders(user, r, mklist<AuthnProviderConf>(AuthnProviderConf(AUTHN_DEFAULT_PROVIDER, provider))); + } + return checkAuthnzProviders(user, r, apcs); +} + +/** * Return the user info for a session. */ const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) { @@ -89,13 +133,13 @@ const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) /** * Handle an authenticated request. */ -const failable<int> authenticated(const list<list<value> >& attrs, const list<list<value> >& info, request_rec* r) { - debug(info, "modoauth2::authenticated::info"); +const failable<int> authenticated(const list<list<value> >& userinfo, const bool check, request_rec* r, const list<list<value> >& scopeattrs, const list<AuthnProviderConf>& apcs) { + debug(userinfo, "modoauth2::authenticated::userinfo"); - if (isNil(attrs)) { + if (isNil(scopeattrs)) { // Store user id in an environment variable - const list<value> id = assoc<value>("id", info); + const list<value> id = assoc<value>("id", userinfo); if (isNil(id) || isNil(cdr(id))) return mkfailure<int>("Couldn't retrieve user id"); apr_table_set(r->subprocess_env, "OAUTH2_ID", apr_pstrdup(r->pool, c_str(cadr(id)))); @@ -104,12 +148,16 @@ const failable<int> authenticated(const list<list<value> >& attrs, const list<li // OAuth id attribute to it if (r->user == NULL || r->user[0] == '\0') r->user = apr_pstrdup(r->pool, c_str(cadr(id))); + + // Run the authnz hooks to check the authenticated user + if (check) + return checkAuthnz(r->user == NULL? "" : r->user, r, apcs); return OK; } - // Store each configure OAuth scope attribute in an environment variable - const list<value> a = car(attrs); - const list<value> v = assoc<value>(cadr(a), info); + // Store each configured OAuth scope attribute in an environment variable + const list<value> a = car(scopeattrs); + const list<value> v = assoc<value>(cadr(a), userinfo); if (!isNil(v) && !isNil(cdr(v))) { // Map the REMOTE_USER attribute to the request user field @@ -118,7 +166,7 @@ const failable<int> authenticated(const list<list<value> >& attrs, const list<li else apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, c_str(car(a))), apr_pstrdup(r->pool, c_str(cadr(v)))); } - return authenticated(cdr(attrs), info, r); + return authenticated(userinfo, check, r, cdr(scopeattrs), apcs); } /** @@ -181,7 +229,8 @@ const failable<list<value> > profileUserInfo(const value& cid, const list<value> /** * Handle an access_token request. */ -const failable<int> accessToken(const list<list<value> >& args, request_rec* r, const list<list<value> >& appkeys, const perthread_ptr<http::CURLSession>& cs, const memcache::MemCached& mc) { +const failable<int> accessToken(const list<list<value> >& args, request_rec* r, const list<list<value> >& appkeys, const perthread_ptr<http::CURLSession>& cs, const list<list<value> >& scopeattrs, const list<AuthnProviderConf>& apcs, const memcache::MemCached& mc) { + // Extract access_token URI, client ID and authorization code parameters const list<value> state = assoc<value>("state", args); if (isNil(state) || isNil(cdr(state))) @@ -245,17 +294,22 @@ const failable<int> accessToken(const list<list<value> >& args, request_rec* r, debug(content(profres), "modoauth2::access_token::info"); // Retrieve the user info from the profile - const failable<list<value> > iv = profileUserInfo(cadr(cid), content(profres)); - if (!hasContent(iv)) - return mkfailure<int>(iv); + const failable<list<value> > userinfo = profileUserInfo(cadr(cid), content(profres)); + if (!hasContent(userinfo)) + return mkfailure<int>(userinfo); - // Store user info in memcached keyed by session ID + // Validate the authenticated user + const failable<int> authrc = authenticated(content(userinfo), true, r, scopeattrs, apcs); + if (!hasContent(authrc)) + return authrc; + + // Store user info in memcached keyed by a session ID const value sid = string("OAuth2_") + mkrand(); - const failable<bool> prc = memcache::put(mklist<value>("tuscanyOAuth2", sid), content(iv), mc); + const failable<bool> prc = memcache::put(mklist<value>("tuscanyOAuth2", sid), content(userinfo), mc); if (!hasContent(prc)) return mkfailure<int>(prc); - // Send session ID to the client in a cookie + // Send the session ID to the client in a cookie debug(c_str(openauth::cookie("TuscanyOAuth2", sid, httpd::hostName(r))), "modoauth2::access_token::setcookie"); apr_table_set(r->err_headers_out, "Set-Cookie", c_str(openauth::cookie("TuscanyOAuth2", sid, httpd::hostName(r)))); return httpd::externalRedirect(httpd::url(httpd::unescape(cadr(ref)), r), r); @@ -265,20 +319,19 @@ const failable<int> accessToken(const list<list<value> >& args, request_rec* r, * Check user authentication. */ static int checkAuthn(request_rec *r) { + gc_scoped_pool pool(r->pool); + // Decline if we're not enabled or AuthType is not set to Open const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth2); if (!dc.enabled) return DECLINED; const char* atype = ap_auth_type(r); - debug(atype, "modopenauth::checkAuthn::auth_type"); if (atype == NULL || strcasecmp(atype, "Open")) return DECLINED; - - // Create a scoped memory pool - gc_scoped_pool pool(r->pool); + debug_httpdRequest(r, "modoauth2::checkAuthn::input"); + debug(atype, "modopenauth::checkAuthn::auth_type"); // Get the server configuration - debug_httpdRequest(r, "modoauth2::checkAuthn::input"); const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth2); // Get session id from the request @@ -288,24 +341,33 @@ static int checkAuthn(request_rec *r) { if (substr(content(sid), 0, 7) != "OAuth2_") return DECLINED; - // If we're authenticated store the user info in the request - const failable<value> info = userInfo(content(sid), sc.mc); - if (hasContent(info)) { - r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(authenticated(dc.scopeattrs, content(info), r)); - } + // Extract the user info from the auth session + const failable<value> userinfo = userInfo(content(sid), sc.mc); + if (!hasContent(userinfo)) + return httpd::reportStatus(mkfailure<int>(userinfo)); + r->ap_auth_type = const_cast<char*>(atype); + return httpd::reportStatus(authenticated(content(userinfo), false, r, dc.scopeattrs, dc.apcs)); } + // Get the request args + const list<list<value> > args = httpd::queryArgs(r); + // Handle OAuth authorize request step if (string(r->uri) == "/oauth2/authorize/") { r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(authorize(httpd::queryArgs(r), r, sc.appkeys)); + return httpd::reportStatus(authorize(args, r, sc.appkeys)); } // Handle OAuth access_token request step if (string(r->uri) == "/oauth2/access_token/") { r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(accessToken(httpd::queryArgs(r), r, sc.appkeys, sc.cs, sc.mc)); + const failable<int> authrc = accessToken(args, r, sc.appkeys, sc.cs, dc.scopeattrs, dc.apcs, sc.mc); + + // Redirect to the login page if user is not authorized + if (!hasContent(authrc) && rcode(authrc) == HTTP_UNAUTHORIZED) + return httpd::reportStatus(openauth::login(dc.login, string("/"), 1, r)); + + return httpd::reportStatus(authrc); } // Redirect to the login page, unless we have a session id or an authorization @@ -316,10 +378,11 @@ static int checkAuthn(request_rec *r) { hasContent(openauth::sessionID(r, "TuscanyOpenAuth")) || hasContent(openauth::sessionID(r, "TuscanyOAuth1"))) return DECLINED; - if ((substr(string(r->uri), 0, 8) == "/oauth1/") || !isNil(assoc<value>("openid_identifier", httpd::queryArgs(r)))) + if ((substr(string(r->uri), 0, 8) == "/oauth1/") || !isNil(assoc<value>("openid_identifier", args))) return DECLINED; + r->ap_auth_type = const_cast<char*>(atype); - return httpd::reportStatus(openauth::login(dc.login, r)); + return httpd::reportStatus(openauth::login(dc.login, value(), value(), r)); } /** @@ -344,6 +407,7 @@ int postConfigMerge(ServerConf& mainsc, server_rec* s) { int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) { gc_scoped_pool pool(p); + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2); debug(httpd::serverName(s), "modoauth2::postConfig::serverName"); @@ -360,7 +424,7 @@ public: } const gc_ptr<http::CURLSession> operator()() const { - return new (gc_new<http::CURLSession>()) http::CURLSession(ca, cert, key, ""); + return new (gc_new<http::CURLSession>()) http::CURLSession(ca, cert, key, "", 0); } private: @@ -374,6 +438,7 @@ private: */ void childInit(apr_pool_t* p, server_rec* s) { gc_scoped_pool pool(p); + ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_oauth2); if(psc == NULL) { cfailure << "[Tuscany] Due to one or more errors mod_tuscany_oauth2 loading failed. Causing apache to stop loading." << endl; @@ -445,11 +510,25 @@ const char* confScopeAttr(cmd_parms *cmd, void* c, const char* arg1, const char* dc.scopeattrs = cons<list<value> >(mklist<value>(arg1, arg2), dc.scopeattrs); return NULL; } +const char* confAuthnProvider(cmd_parms *cmd, void *c, const char* arg) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf<DirConf>(c); + + // Lookup and cache the Authn provider + const authn_provider* provider = (authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, arg, AUTHN_PROVIDER_VERSION); + if (provider == NULL) + return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", arg); + if (!provider->check_password) + return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support password authentication", arg); + dc.apcs = append<AuthnProviderConf>(dc.apcs, mklist<AuthnProviderConf>(AuthnProviderConf(arg, provider))); + return NULL; +} /** * HTTP server module declaration. */ const command_rec commands[] = { + AP_INIT_ITERATE("AuthOAuthProvider", (const char*(*)())confAuthnProvider, NULL, OR_AUTHCFG, "Auth providers for a directory or location"), AP_INIT_TAKE3("AddAuthOAuth2AppKey", (const char*(*)())confAppKey, NULL, RSRC_CONF, "OAuth 2.0 name app-id app-key"), AP_INIT_ITERATE("AddAuthOAuthMemcached", (const char*(*)())confMemcached, NULL, RSRC_CONF, "Memcached server host:port"), AP_INIT_FLAG("AuthOAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "OAuth 2.0 authentication On | Off"), diff --git a/sca-cpp/trunk/modules/oauth/oauth-conf b/sca-cpp/trunk/modules/oauth/oauth-conf index 0b8f14b636..26e654036b 100755 --- a/sca-cpp/trunk/modules/oauth/oauth-conf +++ b/sca-cpp/trunk/modules/oauth/oauth-conf @@ -39,18 +39,23 @@ else sslsuffix="-ssl" fi +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + # Configure HTTPD mod_tuscany_oauth module cat >>$root/conf/modules.conf <<EOF # Generated by: oauth-conf $* # Load support for OAuth authentication -LoadModule mod_tuscany_oauth1 $here/libmod_tuscany_oauth1$libsuffix LoadModule mod_tuscany_oauth2 $here/libmod_tuscany_oauth2$libsuffix EOF # Disallow public access to server resources cat >$root/conf/noauth$sslsuffix.conf <<EOF -# Generated by: oauth-auth-conf $* +# Generated by: oauth-conf $* # Disallow public access to server resources EOF @@ -62,9 +67,12 @@ cat >>$root/conf/locauth$sslsuffix.conf <<EOF <Location /> AuthType Open AuthName "$host" +AuthOAuthProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / Require valid-user AuthOAuth On -AuthOAuthLoginPage /login +AuthOAuthLoginPage /login/ AddAuthOAuth2ScopeAttr REALM realm AddAuthOAuth2ScopeAttr REMOTE_USER email AddAuthOAuth2ScopeAttr EMAIL email @@ -72,13 +80,7 @@ AddAuthOAuth2ScopeAttr NICKNAME name AddAuthOAuth2ScopeAttr FULLNAME name AddAuthOAuth2ScopeAttr FIRSTNAME first_name AddAuthOAuth2ScopeAttr LASTNAME last_name -AddAuthOAuth1ScopeAttr REALM realm -AddAuthOAuth1ScopeAttr REMOTE_USER email -AddAuthOAuth1ScopeAttr EMAIL email -AddAuthOAuth1ScopeAttr NICKNAME screen_name AddAuthOAuth2ScopeAttr FULLNAME name -AddAuthOAuth1ScopeAttr FIRSTNAME first-name -AddAuthOAuth1ScopeAttr LASTNAME last-name </Location> EOF diff --git a/sca-cpp/trunk/modules/oauth/oauth12-conf b/sca-cpp/trunk/modules/oauth/oauth12-conf new file mode 100755 index 0000000000..43c879faee --- /dev/null +++ b/sca-cpp/trunk/modules/oauth/oauth12-conf @@ -0,0 +1,115 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Generate an OAuth server conf +here=`echo "import os; print os.path.realpath('$0')" | python`; here=`dirname $here` +mkdir -p $1 +root=`echo "import os; print os.path.realpath('$1')" | python` + +uname=`uname -s` +if [ $uname = "Darwin" ]; then + libsuffix=".dylib" +else + libsuffix=".so" +fi + +conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"` +host=`echo $conf | awk '{ print $6 }'` + +sslconf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-ssl-conf"` +if [ "$sslconf" = "" ]; then + sslsuffix="" +else + sslsuffix="-ssl" +fi + +if [ "$2" = "" ]; then + providers="file" +else + providers="$2 file" +fi + +# Configure HTTPD mod_tuscany_oauth module +cat >>$root/conf/modules.conf <<EOF +# Generated by: oauth12-conf $* +# Load support for OAuth authentication +LoadModule mod_tuscany_oauth1 $here/libmod_tuscany_oauth1$libsuffix +LoadModule mod_tuscany_oauth2 $here/libmod_tuscany_oauth2$libsuffix + +EOF + +# Disallow public access to server resources +cat >$root/conf/noauth$sslsuffix.conf <<EOF +# Generated by: oauth12-conf $* +# Disallow public access to server resources + +EOF + +# Configure OAuth authentication +cat >>$root/conf/locauth$sslsuffix.conf <<EOF +# Generated by: oauth12-conf $* +# Enable OAuth authentication +<Location /> +AuthType Open +AuthName "$host" +AuthOAuthProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / +Require valid-user +AuthOAuth On +AuthOAuthLoginPage /login/ +AddAuthOAuth2ScopeAttr REALM realm +AddAuthOAuth2ScopeAttr REMOTE_USER email +AddAuthOAuth2ScopeAttr EMAIL email +AddAuthOAuth2ScopeAttr NICKNAME name +AddAuthOAuth2ScopeAttr FULLNAME name +AddAuthOAuth2ScopeAttr FIRSTNAME first_name +AddAuthOAuth2ScopeAttr LASTNAME last_name +AddAuthOAuth1ScopeAttr REALM realm +AddAuthOAuth1ScopeAttr REMOTE_USER email +AddAuthOAuth1ScopeAttr EMAIL email +AddAuthOAuth1ScopeAttr NICKNAME screen_name +AddAuthOAuth2ScopeAttr FULLNAME name +AddAuthOAuth1ScopeAttr FIRSTNAME first-name +AddAuthOAuth1ScopeAttr LASTNAME last-name +</Location> + +EOF + +cat >>$root/conf/auth.conf <<EOF +# Configure OAuth App keys +Include $root/cert/oauth-keys.conf + +EOF + +mkdir -p $root/cert +cat >$root/cert/oauth-keys.conf <<EOF +# Generated by: oauth12-conf $* +# OAuth App keys + +EOF + +if [ -d "$HOME/.oauth" ]; then + cat >>$root/conf/auth.conf <<EOF +# Configure OAuth App keys +Include $HOME/.oauth/*-key.conf + +EOF +fi + diff --git a/sca-cpp/trunk/modules/oauth/start-mixed-test b/sca-cpp/trunk/modules/oauth/start-mixed-test index e5a8837354..478f2cc777 100755 --- a/sca-cpp/trunk/modules/oauth/start-mixed-test +++ b/sca-cpp/trunk/modules/oauth/start-mixed-test @@ -38,7 +38,7 @@ rm -rf tmp ../openid/openid-memcached-conf tmp www.example.com 11212 ../openid/openid-memcached-conf tmp www.example.com 11213 -./oauth-conf tmp +./oauth12-conf tmp ./oauth-memcached-conf tmp www.example.com 11212 ./oauth-memcached-conf tmp www.example.com 11213 @@ -48,13 +48,16 @@ rm -rf tmp ./oauth2-appkey-conf tmp facebook.com app1234 secret6789 ./oauth2-appkey-conf tmp github.com app5678 secret8901 -../http/open-auth-conf tmp -../http/passwd-auth-conf tmp foo foo +../../modules/http/open-auth-conf tmp -# For this test to work you need to add your form, oauth and open id ids -# to the authorized user group +# For this test to work you need to add your oauth and openid user ids to +# the password file with a dummy 'password' password, and to the group +# of authorized users +../../modules/http/passwd-auth-conf tmp foo foo ../../modules/http/group-auth-conf tmp foo +../../modules/http/passwd-auth-conf tmp /openid/123456 password ../../modules/http/group-auth-conf tmp 123456 +../../modules/http/passwd-auth-conf tmp /oauth2/jane@example.com password ../../modules/http/group-auth-conf tmp jane@example.com ../../modules/server/server-conf tmp diff --git a/sca-cpp/trunk/modules/oauth/start-test b/sca-cpp/trunk/modules/oauth/start-test index 8fc41cdb9a..cadbed2bac 100755 --- a/sca-cpp/trunk/modules/oauth/start-test +++ b/sca-cpp/trunk/modules/oauth/start-test @@ -33,7 +33,7 @@ rm -rf tmp ../../modules/http/httpd-conf tmp www.example.com 8090 htdocs ../../modules/http/httpd-ssl-conf tmp 8453 -./oauth-conf tmp +./oauth12-conf tmp ./oauth-memcached-conf tmp www.example.com 11212 ./oauth-memcached-conf tmp www.example.com 11213 @@ -44,7 +44,9 @@ rm -rf tmp ./oauth2-appkey-conf tmp github.com app5678 secret8901 # For this test to work you need to add your oauth user id to the -# authorized user group +# password file with a dummy 'password' password, and to the group +# of authorized users +../../modules/http/passwd-auth-conf tmp /oauth2/jane@example.com password ../../modules/http/group-auth-conf tmp jane@example.com ../../modules/server/server-conf tmp diff --git a/sca-cpp/trunk/modules/openid/openid-conf b/sca-cpp/trunk/modules/openid/openid-conf index d07e4b7cad..7f986fc8d7 100755 --- a/sca-cpp/trunk/modules/openid/openid-conf +++ b/sca-cpp/trunk/modules/openid/openid-conf @@ -33,6 +33,12 @@ else sslsuffix="-ssl" fi +if [ "$2" = "" ]; then + providers="file" +else + providers="$2" +fi + # Configure HTTPD mod_auth_openid module cat >>$root/conf/modules.conf <<EOF # Generated by: openid-conf $* @@ -55,6 +61,9 @@ cat >>$root/conf/locauth$sslsuffix.conf <<EOF <Location /> AuthType Open AuthName "$host" +#AuthOpenIDProvider socache $providers +#AuthnCacheProvideFor $providers +#AuthnCacheContext / Require valid-user AuthOpenIDEnabled On AuthOpenIDCookiePath / diff --git a/sca-cpp/trunk/modules/openid/start-test b/sca-cpp/trunk/modules/openid/start-test index f0d27d16be..56ebbc3736 100755 --- a/sca-cpp/trunk/modules/openid/start-test +++ b/sca-cpp/trunk/modules/openid/start-test @@ -32,8 +32,10 @@ rm -rf tmp ./openid-memcached-conf tmp localhost 11213 ./openid-step2-conf tmp -# For this test to work you need to add your openid (or email address if -# available from your openid attributes to the the authorized user group +# For this test to work you need to add your openid user id to the +# password file with a dummy 'password' password, and to the group +# of authorized users +../../modules/http/passwd-auth-conf tmp /openid/jane@example.com password ../../modules/http/group-auth-conf tmp jane@example.com ../../modules/server/server-conf tmp diff --git a/sca-cpp/trunk/modules/server/mod-eval.hpp b/sca-cpp/trunk/modules/server/mod-eval.hpp index ac5bf55698..ee99baa039 100644 --- a/sca-cpp/trunk/modules/server/mod-eval.hpp +++ b/sca-cpp/trunk/modules/server/mod-eval.hpp @@ -43,6 +43,10 @@ #include "../http/http.hpp" #include "../http/httpd.hpp" +#include "apr_md5.h" +#include "ap_provider.h" +#include "mod_auth.h" + extern "C" { extern module AP_MODULE_DECLARE_DATA mod_tuscany_eval; } @@ -75,8 +79,10 @@ public: string domain; string contribPath; string composName; - string providerName; - value provider; + string contributorName; + value contributor; + string authenticatorName; + value authenticator; }; /** @@ -115,7 +121,7 @@ public: ServerConf() { } - ServerConf(apr_pool_t* p, const server_rec* s) : p(p), server(s) { + ServerConf(apr_pool_t* p, const server_rec* s) : p(p), server(s), timeout(0) { } const gc_pool p; @@ -123,6 +129,7 @@ public: lambda<value(const list<value>&)> lifecycle; ContribConf contribc; SSLConf sslc; + int timeout; VhostConf vhostc; Composite compos; }; @@ -145,7 +152,12 @@ public: }; /** - * Convert a result represented as a content + failure pair to a + * Authentication cache store function. + */ +static APR_OPTIONAL_FN_TYPE(ap_authn_cache_store) *authnCacheStore = NULL; + +/** + * Convert a result represented as a (content reason? code?) tuple to a * failable monad. */ const failable<value> failableResult(const list<value>& v) { @@ -177,9 +189,9 @@ public: /** * Make an HTTP proxy lambda to an absolute URI */ -const value mkhttpProxy(const string& uri, const gc_pool& p) { +const value mkhttpProxy(const string& uri, const int timeout, const gc_pool& p) { debug(uri, "modeval::mkhttpProxy::uri"); - return lambda<value(const list<value>&)>(http::proxy(uri, "", "", "", "", p)); + return lambda<value(const list<value>&)>(http::proxy(uri, "", "", "", "", timeout, p)); } /** @@ -187,7 +199,7 @@ const value mkhttpProxy(const string& uri, const gc_pool& p) { */ class implProxy { public: - implProxy(const value& name, const list<value>& impls, const SSLConf& sslc) : name(name), impls(impls), sslc(sslc) { + implProxy(const value& name, const list<value>& impls, const SSLConf& sslc, const int timeout) : name(name), impls(impls), sslc(sslc), timeout(timeout) { } const value callImpl(const value& cname, const list<value>& aparams) const { @@ -229,7 +241,7 @@ public: ostringstream appuri; appuri << httpd::scheme(currentRequest) << "://" << substr(uri, 6) << "." << http::topDomain(httpd::hostName(currentRequest)) << ":" << httpd::port(currentRequest) << "/"; debug(str(appuri), "modeval::implProxy::httpproxy::appuri"); - const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(str(appuri), sslc.ca, sslc.cert, sslc.key, httpd::cookie(currentRequest), p)); + const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(str(appuri), sslc.ca, sslc.cert, sslc.key, httpd::cookie(currentRequest), timeout, p)); return px(aparams); } @@ -237,13 +249,13 @@ public: // only if the target is in the same top level domain if (http::topDomain(http::hostName(uri, p)) == http::topDomain(httpd::hostName(currentRequest))) { debug(uri, "modeval::implProxy::httpproxy::samedomain"); - const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(uri, sslc.ca, sslc.cert, sslc.key, httpd::cookie(currentRequest), p)); + const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(uri, sslc.ca, sslc.cert, sslc.key, httpd::cookie(currentRequest), timeout, p)); return px(aparams); } // No SSL certificate or cookie on a cross domain call debug(uri, "modeval::implProxy::httpproxy::crossdomain"); - const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(uri, "", "", "", "", p)); + const lambda<value(const list<value>&)> px = lambda<value(const list<value>&)>(http::proxy(uri, "", "", "", "", timeout, p)); return px(aparams); } @@ -259,11 +271,12 @@ private: const value name; const list<value>& impls; const SSLConf& sslc; + const int timeout; }; -const value mkimplProxy(const value& name, const list<value>& impls, const SSLConf& sslc) { +const value mkimplProxy(const value& name, const list<value>& impls, const SSLConf& sslc, const int timeout) { debug(name, "modeval::implProxy::impl"); - return lambda<value(const list<value>&)>(implProxy(name, impls, sslc)); + return lambda<value(const list<value>&)>(implProxy(name, impls, sslc, timeout)); } /** @@ -303,7 +316,7 @@ const value mkunwiredProxy(const string& ref) { /** * Convert a list of component references to a list of proxy lambdas. */ -const value mkrefProxy(const value& ref, const list<value>& impls, const SSLConf& sslc, const gc_pool& p) { +const value mkrefProxy(const value& ref, const list<value>& impls, const SSLConf& sslc, const int timeout, const gc_pool& p) { const value target = scdl::target(ref); const bool wbyimpl = scdl::wiredByImpl(ref); debug(ref, "modeval::mkrefProxy::ref"); @@ -312,18 +325,18 @@ const value mkrefProxy(const value& ref, const list<value>& impls, const SSLConf // Use an HTTP proxy or an internal proxy to the component implementation if (wbyimpl) - return mkimplProxy(value(), impls, sslc); + return mkimplProxy(value(), impls, sslc, timeout); if (isNil(target)) return mkunwiredProxy(scdl::name(ref)); if (http::isAbsolute(target)) - return mkhttpProxy(target, p); - return mkimplProxy(car(pathValues(target)), impls, sslc); + return mkhttpProxy(target, timeout, p); + return mkimplProxy(car(pathValues(target)), impls, sslc, timeout); } -const list<value> refProxies(const list<value>& refs, const list<value>& impls, const SSLConf& sslc, const gc_pool& p) { +const list<value> refProxies(const list<value>& refs, const list<value>& impls, const SSLConf& sslc, const int timeout, const gc_pool& p) { if (isNil(refs)) return refs; - return cons(mkrefProxy(car(refs), impls, sslc, p), refProxies(cdr(refs), impls, sslc, p)); + return cons(mkrefProxy(car(refs), impls, sslc, timeout, p), refProxies(cdr(refs), impls, sslc, timeout, p)); } /** @@ -422,15 +435,29 @@ struct realmPropProxy { const char* env = apr_table_get(currentRequest->subprocess_env, "REALM"); if (env == NULL) return v; - const char* realm = strncmp(env, "www.", 4) == 0? env + 4 : env; - if (*realm == '\0') + const string realm = httpd::realm(string(env)); + if (length(realm) == 0) return v; - const value r = string(realm); + const value r = realm; debug(r, "modeval::realmPropProxy::value"); return r; } }; +struct timeoutPropProxy { + const value v; + timeoutPropProxy(const value& v) : v(atoi(c_str((string)v))) { + } + const value operator()(unused const list<value>& params) const { + if (currentRequest == NULL) + return v; + const ServerConf& sc = httpd::serverConf<ServerConf>(currentRequest, &mod_tuscany_eval); + const value r = sc.timeout; + debug(r, "modeval::timeoutPropProxy::value"); + return r; + } +}; + struct userPropProxy { const value v; userPropProxy(const value& v) : v(v) { @@ -461,6 +488,8 @@ const value mkpropProxy(const value& prop) { return lambda<value(const list<value>&)>(userPropProxy(v)); if (n == "realm") return lambda<value(const list<value>&)>(realmPropProxy(v)); + if (n == "timeout") + return lambda<value(const list<value>&)>(timeoutPropProxy(v)); if (n == "email") return lambda<value(const list<value>&)>(envPropProxy("EMAIL", v)); if (n == "nickname") @@ -499,7 +528,7 @@ struct implementationFailure { } }; -const value evalComponent(const string& contribPath, const value& comp, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const gc_pool& p) { +const value evalComponent(const string& contribPath, const value& comp, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const int timeout, const gc_pool& p) { extern const failable<lambda<value(const list<value>&)> > evalImplementation(const string& cpath, const value& impl, const list<value>& px, const lambda<value(const list<value>&)>& lifecycle); const value impl = scdl::implementation(comp); @@ -507,7 +536,7 @@ const value evalComponent(const string& contribPath, const value& comp, const li debug(impl, "modeval::evalComponent::impl"); // Convert component references to configured proxy lambdas - const list<value> rpx(refProxies(scdl::references(comp), impls, sslc, p)); + const list<value> rpx(refProxies(scdl::references(comp), impls, sslc, timeout, p)); // Convert component properties to configured proxy lambdas const list<value> ppx(propProxies(scdl::properties(comp))); @@ -522,12 +551,12 @@ const value evalComponent(const string& contribPath, const value& comp, const li /** * Return a list of component-name + configured-implementation pairs. */ -const list<value> componentToImplementationAssoc(const list<value>& c, const string& contribPath, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const gc_pool& p) { +const list<value> componentToImplementationAssoc(const list<value>& c, const string& contribPath, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const int timeout, const gc_pool& p) { if (isNil(c)) return c; return cons<value>(mklist<value>(scdl::name(car(c)), - evalComponent(contribPath, car(c), impls, lifecycle, sslc, p)), - componentToImplementationAssoc(cdr(c), contribPath, impls, lifecycle, sslc, p)); + evalComponent(contribPath, car(c), impls, lifecycle, sslc, timeout, p)), + componentToImplementationAssoc(cdr(c), contribPath, impls, lifecycle, sslc, timeout, p)); } /** @@ -541,16 +570,17 @@ const failable<list<value> > readComponents(const string& path) { } /** - * Get the components returned by a provider. + * Get the components returned by a contributor. */ -const failable<list<value> > getComponents(const lambda<value(const list<value>&)>& provider, const string& name) { - const failable<value> val = failableResult(provider(cons<value>("get", mklist<value>(mklist<value>(name))))); +const failable<list<value> > getComponents(const lambda<value(const list<value>&)>& contributor, const string& name) { + const failable<value> val = failableResult(contributor(cons<value>("get", mklist<value>(mklist<value>(name))))); if (!hasContent(val)) return mkfailure<list<value> >(val); - const list<value> c = assoc<value>(value("content"), (list<list<value> >)cdr<value>(content(val))); + const list<value> c = assoc<value>(value("composite"), assoc<value>(value("content"), (list<list<value> >)cdr<value>(car<value>(content(val))))); + debug(c, "modeval::getComponents::comp"); if (isNil(c)) return mkfailure<list<value> >(string("Could not get composite: ") + name); - const failable<list<string> > x = writeXML(car<value>(valuesToElements(mklist<value>(mklist<value>(cadr(c)))))); + const failable<list<string> > x = writeXML(car<value>(valuesToElements(mklist<value>(mklist<value>(c))))); if (!hasContent(x)) return mkfailure<list<value> >(x); return scdl::components(readXML(content(x))); @@ -631,16 +661,16 @@ const list<value> uriToComponentAssoc(const list<value>& c) { /** * Configure the components declared in the deployed composite. */ -const failable<Composite> confComponents(const string& contribPath, const string& composName, const value& provider, const string& vhost, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const gc_pool& p) { +const failable<Composite> confComponents(const string& contribPath, const string& composName, const value& contributor, const string& vhost, const list<value>& impls, const lambda<value(const list<value>&)> lifecycle, const SSLConf& sslc, const int timeout, const gc_pool& p) { debug(contribPath, "modeval::confComponents::contribPath"); debug(composName, "modeval::confComponents::composName"); - debug(provider, "modeval::confComponents::provider"); + debug(contributor, "modeval::confComponents::contributor"); debug(vhost, "modeval::confComponents::vhost"); debug(impls, "modeval::confComponents::impls"); - const failable<list<value> > fcomps = isNil(provider)? + const failable<list<value> > fcomps = isNil(contributor)? readComponents(scdl::resourcePath(length(vhost) != 0? contribPath + vhost + "/" : contribPath, composName)) : - getComponents(provider, vhost); + getComponents(contributor, vhost); if (!hasContent(fcomps)) return mkfailure<Composite>(fcomps); @@ -654,8 +684,8 @@ const failable<Composite> confComponents(const string& contribPath, const string debug(flatten(svcs), "modeval::confComponents::svcs"); const list<value> cimpls = mkbtree(sort(componentToImplementationAssoc(comps, - isNil(provider)? length(vhost) != 0? contribPath + vhost + "/" : contribPath : contribPath, - impls, lifecycle, sslc, p))); + isNil(contributor)? length(vhost) != 0? contribPath + vhost + "/" : contribPath : contribPath, + impls, lifecycle, sslc, timeout, p))); debug(flatten(cimpls), "modeval::confComponents::impls"); return Composite(refs, svcs, cimpls); @@ -720,6 +750,10 @@ const failable<int> get(const list<value>& rpath, request_rec* r, const lambda<v const value c = content(val); debug(c, "modeval::get::content"); + // Return a nil value as a not found status + if (!isList(c) && isNil(c)) + return HTTP_NOT_FOUND; + // Check if the client requested a specific format const list<value> fmt = assoc<value>("format", args); @@ -735,6 +769,7 @@ const failable<int> get(const list<value>& rpath, request_rec* r, const lambda<v debug(lc, "modeval::get::symbol"); return httpd::writeResult(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8", r); } + const list<value> lc = mklist<value>(mklist<value>("value", c)); debug(lc, "modeval::get::value"); return httpd::writeResult(json::writeJSON(valuesToElements(lc), cx), "application/json; charset=utf-8", r); @@ -1041,9 +1076,9 @@ const int translateRequest(request_rec* r, const list<value>& rpath, const list< // Attempt to map a request targeting the main host to an actual file if (isNil(vpath)) { - const failable<request_rec*, int> fnr = httpd::internalSubRequest(r->uri, r); + const failable<request_rec*> fnr = httpd::internalSubRequest(r->uri, r); if (!hasContent(fnr)) - return HTTP_INTERNAL_SERVER_ERROR; + return rcode(fnr); request_rec* nr = content(fnr); nr->uri = r->filename; const int tr = ap_core_translate(nr); @@ -1082,7 +1117,6 @@ int translate(request_rec *r) { if(r->method_number != M_GET && r->method_number != M_POST && r->method_number != M_PUT && r->method_number != M_DELETE) return DECLINED; - // Create a scoped memory pool gc_scoped_pool pool(r->pool); debug_httpdRequest(r, "modeval::translate::input"); @@ -1103,9 +1137,9 @@ int translate(request_rec *r) { // If the request is targeting a virtual host, configure the components // in that virtual host - if (length(sc.vhostc.domain) != 0 && (length(sc.vhostc.contribPath) != 0 || !isNil(sc.vhostc.provider)) && httpd::isVhostRequest(sc.server, sc.vhostc.domain, r)) { + if (length(sc.vhostc.domain) != 0 && (length(sc.vhostc.contribPath) != 0 || !isNil(sc.vhostc.contributor)) && httpd::isVhostRequest(sc.server, sc.vhostc.domain, r)) { const string vname = http::subDomain(httpd::hostName(r)); - const failable<Composite> fvcompos = confComponents(sc.vhostc.contribPath, sc.vhostc.composName, sc.vhostc.provider, vname, reqc.impls, sc.lifecycle, sc.sslc, sc.p); + const failable<Composite> fvcompos = confComponents(sc.vhostc.contribPath, sc.vhostc.composName, sc.vhostc.contributor, vname, reqc.impls, sc.lifecycle, sc.sslc, sc.timeout, sc.p); if (!hasContent(fvcompos)) return DECLINED; const Composite vcompos = content(fvcompos); @@ -1124,9 +1158,9 @@ int translate(request_rec *r) { return rc; // Attempt to map the first segment of the request path to a virtual host - if (length(prefix) != 0 && (length(sc.vhostc.contribPath) != 0 || !isNil(sc.vhostc.provider))) { + if (length(prefix) != 0 && (length(sc.vhostc.contribPath) != 0 || !isNil(sc.vhostc.contributor))) { const string vname = prefix; - const failable<Composite> fvcompos = confComponents(sc.vhostc.contribPath, sc.vhostc.composName, sc.vhostc.provider, vname, reqc.impls, sc.lifecycle, sc.sslc, sc.p); + const failable<Composite> fvcompos = confComponents(sc.vhostc.contribPath, sc.vhostc.composName, sc.vhostc.contributor, vname, reqc.impls, sc.lifecycle, sc.sslc, sc.timeout, sc.p); if (!hasContent(fvcompos)) return DECLINED; const Composite vcompos = content(fvcompos); @@ -1150,9 +1184,9 @@ const int handleRequest(const list<value>& rpath, request_rec *r, const list<val mkfailure<int>(string("Couldn't find component implementation: ") + cadr(rpath)); return HTTP_NOT_FOUND; } + const lambda<value(const list<value>&)> l(cadr<value>(impl)); // Handle HTTP method - const lambda<value(const list<value>&)> l(cadr<value>(impl)); if (r->header_only) return OK; if(r->method_number == M_GET) @@ -1182,7 +1216,7 @@ int handler(request_rec *r) { if(strcmp(r->handler, "mod_tuscany_eval")) return DECLINED; - // Create a scoped memory pool and a scope for the current request + // Create a scope for the current request gc_scoped_pool pool(r->pool); ScopedRequest sr(r); @@ -1228,6 +1262,61 @@ int handler(request_rec *r) { } /** + * Call an authenticator component to check a user's password. + */ +authn_status checkPassword(request_rec* r, const char* u, const char* p) { + gc_scoped_pool pool(r->pool); + + // Prevent FakeBasicAuth spoofing + const string user = u; + const string password = p; + debug(user, "modeval::checkPassword::user"); + if (substr(user, 0, 1) != "/" && find(user, "/") != length(user) && password == "password") { + mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED); + return AUTH_DENIED; + } + + // Get the server configuration + const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval); + if (isNil(sc.vhostc.authenticator)) { + mkfailure<int>("SCA authenticator not configured"); + return AUTH_GENERAL_ERROR; + } + + // Retrieve the user's password hash + const list<value> uid = pathValues(user); + const failable<value> val = failableResult(sc.vhostc.authenticator(cons<value>("get", mklist<value>(uid)))); + if (!hasContent(val)) { + mkfailure<int>(string("SCA authentication check user failed, user not found: ") + user); + return AUTH_USER_NOT_FOUND; + } + const value hval = content(val); + const list<value> hcontent = isList(hval) && !isNil(hval) && isList(car<value>(hval)) && !isNil(car<value>(hval))? assoc<value>(value("content"), cdr<value>(car<value>(hval))) : list<value>(); + const list<value> hassoc = isNil(hcontent)? list<value>() : assoc<value>(value("hash"), cdr<value>(hcontent)); + if (isNil(hassoc)) { + mkfailure<int>(string("SCA authentication check user failed, hash not found: ") + user); + return AUTH_USER_NOT_FOUND; + } + const string hash = cadr<value>(hassoc); + if (length(hash) == 0) { + mkfailure<int>(string("SCA authentication check user failed: ") + user); + return AUTH_USER_NOT_FOUND; + } + + // Cache the hash in the auth cache provider, if available + if (authnCacheStore != NULL) + authnCacheStore(r, "component", u, NULL, c_str(hash)); + + // Validate the presented password against the hash + const apr_status_t rv = apr_password_validate(p, c_str(hash)); + if (rv != APR_SUCCESS) { + mkfailure<int>(string("SCA authentication user password check failed: ") + user); + return AUTH_DENIED; + } + return AUTH_GRANTED; +} + +/** * Cleanup callback, called when the server is stopped or restarted. */ apr_status_t serverCleanup(void* v) { @@ -1262,6 +1351,7 @@ const int postConfigMerge(const ServerConf& mainsc, server_rec* s) { if (sc.sslc.ca == "") sc.sslc.ca = mainsc.sslc.ca; if (sc.sslc.cert == "") sc.sslc.cert = mainsc.sslc.cert; if (sc.sslc.key == "") sc.sslc.key = mainsc.sslc.key; + sc.timeout = mainsc.timeout; sc.compos = mainsc.compos; return postConfigMerge(mainsc, s->next); } @@ -1311,7 +1401,7 @@ int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, } // Configure the deployed components - const failable<Composite> compos = confComponents(sc.contribc.contribPath, sc.contribc.composName, value(), "", sc.compos.impls, sc.lifecycle, sc.sslc, sc.p); + const failable<Composite> compos = confComponents(sc.contribc.contribPath, sc.contribc.composName, value(), "", sc.compos.impls, sc.lifecycle, sc.sslc, sc.timeout, sc.p); if (!hasContent(compos)) { cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; return -1; @@ -1326,28 +1416,49 @@ int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, } /** + * Exit after a failure. + */ +void failureExitChild() { + cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; + exit(APEXIT_CHILDFATAL); +} + +/** * Child process initialization. */ void childInit(apr_pool_t* p, server_rec* s) { gc_scoped_pool pool(p); + ServerConf* psc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_eval); - if(psc == NULL) { - cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; - exit(APEXIT_CHILDFATAL); - } + if(psc == NULL) + failureExitChild(); ServerConf& sc = *psc; // Start the components in the child process const failable<list<value> > fsimpls = startComponents(sc.compos.impls); - if (!hasContent(fsimpls)) { - cfailure << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; - exit(APEXIT_CHILDFATAL); - } + if (!hasContent(fsimpls)) + failureExitChild(); sc.compos.impls = content(fsimpls); - // Create a proxy for the vhost provider if needed - if (length(sc.vhostc.providerName) != 0) - sc.vhostc.provider = mkimplProxy(sc.vhostc.providerName, sc.compos.impls, sc.sslc); + // Get the vhost contributor component implementation lambda + if (length(sc.vhostc.contributorName) != 0) { + const list<value> impl(assoctree<value>(sc.vhostc.contributorName, sc.compos.impls)); + if (isNil(impl)) { + mkfailure<int>(string("Couldn't find contributor component implementation: ") + sc.vhostc.contributorName); + failureExitChild(); + } + sc.vhostc.contributor = cadr<value>(impl); + } + + // Get the vhost authenticator component implementation lambda + if (length(sc.vhostc.authenticatorName) != 0) { + const list<value> impl(assoctree<value>(sc.vhostc.authenticatorName, sc.compos.impls)); + if (isNil(impl)) { + mkfailure<int>(string("Couldn't find authenticator component implementation: ") + sc.vhostc.authenticatorName); + failureExitChild(); + } + sc.vhostc.authenticator = cadr<value>(impl); + } // Merge the updated configuration into the virtual hosts postConfigMerge(sc, s->next); @@ -1383,10 +1494,10 @@ const char* confVirtualContribution(cmd_parms *cmd, unused void *c, const char * sc.vhostc.contribPath = arg; return NULL; } -const char* confVirtualprovider(cmd_parms *cmd, unused void *c, const char *arg) { +const char* confVirtualContributor(cmd_parms *cmd, unused void *c, const char *arg) { gc_scoped_pool pool(cmd->pool); ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); - sc.vhostc.providerName = arg; + sc.vhostc.contributorName = arg; return NULL; } const char* confVirtualComposite(cmd_parms *cmd, unused void *c, const char *arg) { @@ -1395,6 +1506,12 @@ const char* confVirtualComposite(cmd_parms *cmd, unused void *c, const char *arg sc.vhostc.composName = arg; return NULL; } +const char* confAuthenticator(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + sc.vhostc.authenticatorName = arg; + return NULL; +} const char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) { gc_scoped_pool pool(cmd->pool); ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); @@ -1413,6 +1530,12 @@ const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) { sc.sslc.key = arg; return NULL; } +const char* confTimeout(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + sc.timeout = atoi(arg); + return NULL; +} const char* confEnv(unused cmd_parms *cmd, unused void *c, const char *name, const char *value) { gc_scoped_pool pool(cmd->pool); setenv(name, value != NULL? value : "", 1); @@ -1427,20 +1550,33 @@ const command_rec commands[] = { AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, RSRC_CONF, "SCA composite location"), AP_INIT_TAKE1("SCAVirtualDomain", (const char*(*)())confVirtualDomain, NULL, RSRC_CONF, "SCA virtual host domain"), AP_INIT_TAKE1("SCAVirtualContribution", (const char*(*)())confVirtualContribution, NULL, RSRC_CONF, "SCA virtual host contribution path"), - AP_INIT_TAKE1("SCAVirtualContributor", (const char*(*)())confVirtualprovider, NULL, RSRC_CONF, "SCA virtual host provider component"), + AP_INIT_TAKE1("SCAVirtualContributor", (const char*(*)())confVirtualContributor, NULL, RSRC_CONF, "SCA virtual host contributor component"), AP_INIT_TAKE1("SCAVirtualComposite", (const char*(*)())confVirtualComposite, NULL, RSRC_CONF, "SCA virtual composite location"), + AP_INIT_TAKE1("SCAAuthenticator", (const char*(*)())confAuthenticator, NULL, RSRC_CONF, "SCA authenticator component"), AP_INIT_TAKE12("SCASetEnv", (const char*(*)())confEnv, NULL, OR_FILEINFO, "Environment variable name and optional value"), AP_INIT_TAKE1("SCAWiringSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "SCA wiring SSL CA certificate file"), AP_INIT_TAKE1("SCAWiringSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "SCA wiring SSL certificate file"), AP_INIT_TAKE1("SCAWiringSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "SCA wiring SSL certificate key file"), + AP_INIT_TAKE1("SCAWiringTimeout", (const char*(*)())confTimeout, NULL, RSRC_CONF, "SCA wiring timeout"), {NULL, NULL, NULL, 0, NO_ARGS, NULL} }; +const authn_provider AuthnProvider = { + &checkPassword, + NULL +}; + +void retrieveAuthnCacheStore() { + authnCacheStore = APR_RETRIEVE_OPTIONAL_FN(ap_authn_cache_store); +} + void registerHooks(unused apr_pool_t *p) { ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_register_auth_provider(p, AUTHN_PROVIDER_GROUP, "component", AUTHN_PROVIDER_VERSION, &AuthnProvider, AP_AUTH_INTERNAL_PER_CONF); + ap_hook_optional_fn_retrieve(retrieveAuthnCacheStore, NULL, NULL, APR_HOOK_MIDDLE); } } diff --git a/sca-cpp/trunk/samples/store-cluster/tunnel-ssl-conf b/sca-cpp/trunk/samples/store-cluster/tunnel-ssl-conf index 7a9a8ad305..f798fdab0b 100755 --- a/sca-cpp/trunk/samples/store-cluster/tunnel-ssl-conf +++ b/sca-cpp/trunk/samples/store-cluster/tunnel-ssl-conf @@ -28,5 +28,6 @@ set -x ../../modules/http/httpd-event-conf $root tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C $root -x ../../modules/http/httpd-ssl-conf $root $sslport +../../modules/http/httpd-tunnel-ssl-conf $root ../../modules/http/cert-auth-conf $root |