From 11522a4b90a4056319cdbc204fffc63780cbfa51 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Mon, 16 Jul 2012 06:47:49 +0000 Subject: Add an HTTPD auth provider allowing the authentication logic to be implemented by a component, and cleanup the SSL and mod-security config a bit. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1361915 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/.gitignore | 1 + sca-cpp/trunk/components/cache/memcached-ssl-test | 2 + sca-cpp/trunk/hosting/server/Makefile.am | 36 ++- sca-cpp/trunk/hosting/server/authn.py | 40 ++++ .../server/data/accounts/admin/user.account | 1 + .../hosting/server/data/accounts/jane/user.account | 1 + .../data/accounts/jane@localhost/user.account | 1 - .../data/accounts/jane@sca-store.com/user.account | 1 - .../hosting/server/data/accounts/john/user.account | 1 + .../data/accounts/john@localhost/user.account | 1 - .../data/accounts/john@sca-store.com/user.account | 1 - sca-cpp/trunk/hosting/server/delete-auth | 61 +++++ sca-cpp/trunk/hosting/server/get-auth | 62 +++++ sca-cpp/trunk/hosting/server/put-auth | 80 +++++++ sca-cpp/trunk/hosting/server/server.composite | 51 +--- sca-cpp/trunk/hosting/server/ssl-start | 113 +++++---- sca-cpp/trunk/hosting/server/user.py | 6 +- sca-cpp/trunk/modules/http/basic-auth-conf | 15 +- sca-cpp/trunk/modules/http/cert-auth-conf | 10 +- sca-cpp/trunk/modules/http/form-auth-conf | 14 +- sca-cpp/trunk/modules/http/httpd-ssl-conf | 26 +-- sca-cpp/trunk/modules/http/httpd-tunnel-ssl-conf | 38 +++ sca-cpp/trunk/modules/http/mod-openauth.cpp | 189 +++++++++------ sca-cpp/trunk/modules/http/mod-security-conf | 28 +-- sca-cpp/trunk/modules/http/open-auth-conf | 22 +- sca-cpp/trunk/modules/http/openauth.hpp | 10 +- sca-cpp/trunk/modules/http/passwd-auth-conf | 2 +- sca-cpp/trunk/modules/oauth/Makefile.am | 2 +- sca-cpp/trunk/modules/oauth/mod-oauth1.cpp | 139 ++++++++--- sca-cpp/trunk/modules/oauth/mod-oauth2.cpp | 141 ++++++++--- sca-cpp/trunk/modules/oauth/oauth-conf | 20 +- sca-cpp/trunk/modules/oauth/oauth12-conf | 115 +++++++++ sca-cpp/trunk/modules/oauth/start-mixed-test | 13 +- sca-cpp/trunk/modules/oauth/start-test | 6 +- sca-cpp/trunk/modules/openid/openid-conf | 9 + sca-cpp/trunk/modules/openid/start-test | 6 +- sca-cpp/trunk/modules/server/mod-eval.hpp | 258 ++++++++++++++++----- .../trunk/samples/store-cluster/tunnel-ssl-conf | 1 + 38 files changed, 1156 insertions(+), 367 deletions(-) create mode 100644 sca-cpp/trunk/hosting/server/authn.py create mode 100644 sca-cpp/trunk/hosting/server/data/accounts/admin/user.account create mode 100644 sca-cpp/trunk/hosting/server/data/accounts/jane/user.account delete mode 100644 sca-cpp/trunk/hosting/server/data/accounts/jane@localhost/user.account delete mode 100644 sca-cpp/trunk/hosting/server/data/accounts/jane@sca-store.com/user.account create mode 100644 sca-cpp/trunk/hosting/server/data/accounts/john/user.account delete mode 100644 sca-cpp/trunk/hosting/server/data/accounts/john@localhost/user.account delete mode 100644 sca-cpp/trunk/hosting/server/data/accounts/john@sca-store.com/user.account create mode 100755 sca-cpp/trunk/hosting/server/delete-auth create mode 100755 sca-cpp/trunk/hosting/server/get-auth create mode 100755 sca-cpp/trunk/hosting/server/put-auth create mode 100755 sca-cpp/trunk/modules/http/httpd-tunnel-ssl-conf create mode 100755 sca-cpp/trunk/modules/oauth/oauth12-conf (limited to 'sca-cpp') 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 < + + $user + $user + + $hash + + +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 @@ ? ? ? - - - - + @@ -49,7 +46,7 @@ - + @@ -59,18 +56,17 @@ - - - + + + + + - - - @@ -78,9 +74,6 @@ - - - @@ -88,9 +81,6 @@ - - - @@ -101,9 +91,6 @@ - - - @@ -111,9 +98,6 @@ - - - @@ -121,17 +105,11 @@ - - - - - - @@ -140,9 +118,6 @@ - - - @@ -151,9 +126,6 @@ - - - localhost:11211 localhost:11212 @@ -162,25 +134,16 @@ data scheme - - - data xml - - - - - - 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 <tmp/conf/log-ssl.conf <tmp/conf/mod-security-log.conf <>tmp/conf/svhost-ssl.conf <>tmp/conf/svhost-ssl.conf <tmp/conf/adminauth.conf < +AuthType None +Require all granted + + + +AuthType None +Require all granted + + +EOF + +# Configure admin access to components +cat >>tmp/conf/locauth-ssl.conf < +Require user admin + + +Require user admin + + +Require valid-user + + +Require valid-user + +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 < AuthType Basic AuthName "$host" -AuthBasicProvider file +AuthBasicProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / Require valid-user 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 < AuthType Basic AuthName "$host" -AuthBasicProvider file +AuthBasicProvider socache $providers +AuthnCacheProvideFor $providers +AuthnCacheContext / Require valid-user 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 < 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 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 <$root/conf/dvhost-ssl.conf <>$root/conf/modules.conf < apcs; }; #ifdef WANT_MAINTAINER_LOG @@ -100,11 +116,40 @@ const bool debugSession(request_rec* r, session_rec* z) { #endif +/** + * Run the authnz hooks to authenticate a request. + */ +const failable checkAuthnzProviders(const string& user, const string& pw, request_rec* r, const list& apcs) { + if (isNil(apcs)) + return mkfailure("Authentication failure for: " + user); + const AuthnProviderConf apc = car(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 checkAuthnz(const string& user, const string& pw, request_rec* r, const DirConf& dc) { + if (substr(user, 0, 1) == "/" && pw == "password") + return mkfailure(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(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 userInfoFromSession(const string& realm, request_rec* r) { debug("modopenauth::userInfoFromSession"); @@ -185,37 +230,24 @@ const failable authenticated(const list >& info, request_rec* r return OK; } -/** - * Run the authnz hooks to try to authenticate a request. - */ -const failable 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("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("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(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 > args = httpd::queryArgs(r); // Get session id from the request const maybe sid = sessionID(r, "TuscanyOpenAuth"); @@ -231,17 +263,17 @@ static int checkAuthn(request_rec *r) { return httpd::reportStatus(mkfailure("Missing AuthName")); // Extract user info from the session id - const failable info = userInfoFromCookie(content(sid), aname, r); - if (hasContent(info)) { + const failable userinfo = userInfoFromCookie(content(sid), aname, r); + if (hasContent(userinfo)) { // Try to authenticate the request - const value uinfo = content(info); - const failable authz = checkAuthnz(cadr(assoc("id", uinfo)), cadr(assoc("password", uinfo)), r); + const value uinfo = content(userinfo); + const failable authz = checkAuthnz(cadr(assoc("id", uinfo)), cadr(assoc("password", uinfo)), r, dc); if (!hasContent(authz)) { // Authentication failed, redirect to login page r->ap_auth_type = const_cast(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 authz = checkAuthnz(cadr(assoc("id", uinfo)), cadr(assoc("password", uinfo)), r); + const failable authz = checkAuthnz(cadr(assoc("id", uinfo)), cadr(assoc("password", uinfo)), r, dc); if (!hasContent(authz)) { // Authentication failed, redirect to login page r->ap_auth_type = const_cast(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 > args = httpd::queryArgs(r); - // Decline if the request is for another authentication provider if (!isNil(assoc("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(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(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(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(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 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(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(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(dc.apcs, mklist(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 <>$root/conf/locauth$sslsuffix.conf < 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 @@ -79,8 +87,10 @@ Require valid-user 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 login(const string& page, request_rec* r) { - const list > largs = mklist >(mklist("openauth_referrer", httpd::escape(httpd::url(r->uri, r)))); - const string loc = httpd::url(page, r) + string("?") + http::queryString(largs); +const failable login(const string& page, const value& ref, const value& attempt, request_rec* r) { + const list > rarg = ref == string("/")? list >() : mklist >(mklist("openauth_referrer", httpd::escape(httpd::url(isNil(ref)? r->uri : ref, r)))); + const list > aarg = isNil(attempt)? list >() : mklist >(mklist("openauth_attempt", attempt)); + const list > largs = append >(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 @@ -70,6 +70,20 @@ public: perthread_ptr cs; }; +/** + * 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. */ @@ -83,8 +97,38 @@ public: bool enabled; string login; list > scopeattrs; + list apcs; }; +/** + * Run the authnz hooks to authenticate a request. + */ +const failable checkAuthnzProviders(const string& user, request_rec* r, const list& apcs) { + if (isNil(apcs)) + return mkfailure("Authentication failure for: " + user, HTTP_UNAUTHORIZED); + const AuthnProviderConf apc = car(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 checkAuthnz(const string& user, request_rec* r, const list& apcs) { + if (substr(user, 0, 1) == "/") + return mkfailure(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(AUTHN_DEFAULT_PROVIDER, provider))); + } + return checkAuthnzProviders(user, r, apcs); +} + /** * Return the user info for a session. */ @@ -95,27 +139,31 @@ const failable userInfo(const value& sid, const memcache::MemCached& mc) /** * Handle an authenticated request. */ -const failable authenticated(const list >& attrs, const list >& info, request_rec* r) { - debug(info, "modoauth1::authenticated::info"); +const failable authenticated(const list >& userinfo, const bool check, request_rec* r, const list >& scopeattrs, const list& apcs) { + debug(userinfo, "modoauth2::authenticated::userinfo"); - if (isNil(attrs)) { + if (isNil(scopeattrs)) { // Store user id in an environment variable - const list id = assoc("id", info); + const list id = assoc("id", userinfo); if (isNil(id) || isNil(cdr(id))) return mkfailure("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 a = car(attrs); - const list v = assoc(cadr(a), info); + // Store each configured OAuth scope attribute in an environment variable + const list a = car(scopeattrs); + const list v = assoc(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 authenticated(const list >& attrs, const list
  • 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 > profileUserInfo(const value& cid, const string& inf /** * Handle an access_token request. */ -const failable accessToken(const list >& args, request_rec* r, const list >& appkeys, const memcache::MemCached& mc) { +const failable accessToken(const list >& args, request_rec* r, const list >& appkeys, const list >& scopeattrs, const list& apcs, const memcache::MemCached& mc) { + // Extract access_token URI, client ID and verification code const list ref = assoc("openauth_referrer", args); if (isNil(ref) || isNil(cdr(ref))) @@ -372,13 +421,18 @@ const failable accessToken(const list >& args, request_rec* r, debug(profres, "modoauth1::access_token::profres"); // Retrieve the user info from the profile - const failable > iv = profileUserInfo(cadr(cid), profres); - if (!hasContent(iv)) - return mkfailure(iv); + const failable > userinfo = profileUserInfo(cadr(cid), profres); + if (!hasContent(userinfo)) + return mkfailure(userinfo); + + // Validate the authenticated user + const failable 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 prc = memcache::put(mklist("tuscanyOAuth1", sid), content(iv), mc); + const failable prc = memcache::put(mklist("tuscanyOAuth1", sid), content(userinfo), mc); if (!hasContent(prc)) return mkfailure(prc); @@ -392,20 +446,19 @@ const failable accessToken(const list >& 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(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(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 info = userInfo(content(sid), sc.mc); - if (hasContent(info)) { - r->ap_auth_type = const_cast(atype); - return httpd::reportStatus(authenticated(dc.scopeattrs, content(info), r)); - } + // Extract the user info from the auth session + const failable userinfo = userInfo(content(sid), sc.mc); + if (!hasContent(userinfo)) + return httpd::reportStatus(mkfailure(userinfo)); + r->ap_auth_type = const_cast(atype); + return httpd::reportStatus(authenticated(content(userinfo), false, r, dc.scopeattrs, dc.apcs)); } + // Get the request args + const list > args = httpd::queryArgs(r); + // Handle OAuth authorize request step if (string(r->uri) == "/oauth1/authorize/") { r->ap_auth_type = const_cast(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(atype); - return httpd::reportStatus(accessToken(httpd::queryArgs(r), r, sc.appkeys, sc.mc)); + const failable 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("openid_identifier", httpd::queryArgs(r)))) + if ((substr(string(r->uri), 0, 8) == "/oauth2/") || !isNil(assoc("openid_identifier", args))) return DECLINED; + r->ap_auth_type = const_cast(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(s, &mod_tuscany_oauth1); debug(httpd::serverName(s), "modoauth1::postConfig::serverName"); @@ -487,7 +551,7 @@ public: } const gc_ptr operator()() const { - return new (gc_new()) http::CURLSession(ca, cert, key, ""); + return new (gc_new()) 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 >(mklist(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(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(dc.apcs, mklist(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 @@ -64,6 +64,20 @@ public: perthread_ptr cs; }; +/** + * 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. */ @@ -77,8 +91,38 @@ public: bool enabled; string login; list > scopeattrs; + list apcs; }; +/** + * Run the authnz hooks to authenticate a request. + */ +const failable checkAuthnzProviders(const string& user, request_rec* r, const list& apcs) { + if (isNil(apcs)) + return mkfailure("Authentication failure for: " + user, HTTP_UNAUTHORIZED); + const AuthnProviderConf apc = car(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 checkAuthnz(const string& user, request_rec* r, const list& apcs) { + if (substr(user, 0, 1) == "/") + return mkfailure(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(AUTHN_DEFAULT_PROVIDER, provider))); + } + return checkAuthnzProviders(user, r, apcs); +} + /** * Return the user info for a session. */ @@ -89,13 +133,13 @@ const failable userInfo(const value& sid, const memcache::MemCached& mc) /** * Handle an authenticated request. */ -const failable authenticated(const list >& attrs, const list >& info, request_rec* r) { - debug(info, "modoauth2::authenticated::info"); +const failable authenticated(const list >& userinfo, const bool check, request_rec* r, const list >& scopeattrs, const list& apcs) { + debug(userinfo, "modoauth2::authenticated::userinfo"); - if (isNil(attrs)) { + if (isNil(scopeattrs)) { // Store user id in an environment variable - const list id = assoc("id", info); + const list id = assoc("id", userinfo); if (isNil(id) || isNil(cdr(id))) return mkfailure("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 authenticated(const list >& attrs, const list
  • 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 a = car(attrs); - const list v = assoc(cadr(a), info); + // Store each configured OAuth scope attribute in an environment variable + const list a = car(scopeattrs); + const list v = assoc(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 authenticated(const list >& attrs, const list
  • 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 > profileUserInfo(const value& cid, const list /** * Handle an access_token request. */ -const failable accessToken(const list >& args, request_rec* r, const list >& appkeys, const perthread_ptr& cs, const memcache::MemCached& mc) { +const failable accessToken(const list >& args, request_rec* r, const list >& appkeys, const perthread_ptr& cs, const list >& scopeattrs, const list& apcs, const memcache::MemCached& mc) { + // Extract access_token URI, client ID and authorization code parameters const list state = assoc("state", args); if (isNil(state) || isNil(cdr(state))) @@ -245,17 +294,22 @@ const failable accessToken(const list >& args, request_rec* r, debug(content(profres), "modoauth2::access_token::info"); // Retrieve the user info from the profile - const failable > iv = profileUserInfo(cadr(cid), content(profres)); - if (!hasContent(iv)) - return mkfailure(iv); + const failable > userinfo = profileUserInfo(cadr(cid), content(profres)); + if (!hasContent(userinfo)) + return mkfailure(userinfo); - // Store user info in memcached keyed by session ID + // Validate the authenticated user + const failable 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 prc = memcache::put(mklist("tuscanyOAuth2", sid), content(iv), mc); + const failable prc = memcache::put(mklist("tuscanyOAuth2", sid), content(userinfo), mc); if (!hasContent(prc)) return mkfailure(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 accessToken(const list >& 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(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(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 info = userInfo(content(sid), sc.mc); - if (hasContent(info)) { - r->ap_auth_type = const_cast(atype); - return httpd::reportStatus(authenticated(dc.scopeattrs, content(info), r)); - } + // Extract the user info from the auth session + const failable userinfo = userInfo(content(sid), sc.mc); + if (!hasContent(userinfo)) + return httpd::reportStatus(mkfailure(userinfo)); + r->ap_auth_type = const_cast(atype); + return httpd::reportStatus(authenticated(content(userinfo), false, r, dc.scopeattrs, dc.apcs)); } + // Get the request args + const list > args = httpd::queryArgs(r); + // Handle OAuth authorize request step if (string(r->uri) == "/oauth2/authorize/") { r->ap_auth_type = const_cast(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(atype); - return httpd::reportStatus(accessToken(httpd::queryArgs(r), r, sc.appkeys, sc.cs, sc.mc)); + const failable 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("openid_identifier", httpd::queryArgs(r)))) + if ((substr(string(r->uri), 0, 8) == "/oauth1/") || !isNil(assoc("openid_identifier", args))) return DECLINED; + r->ap_auth_type = const_cast(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(s, &mod_tuscany_oauth2); debug(httpd::serverName(s), "modoauth2::postConfig::serverName"); @@ -360,7 +424,7 @@ public: } const gc_ptr operator()() const { - return new (gc_new()) http::CURLSession(ca, cert, key, ""); + return new (gc_new()) 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 >(mklist(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(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(dc.apcs, mklist(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 <$root/conf/noauth$sslsuffix.conf <>$root/conf/locauth$sslsuffix.conf < 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 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 <$root/conf/noauth$sslsuffix.conf <>$root/conf/locauth$sslsuffix.conf < +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 + + +EOF + +cat >>$root/conf/auth.conf <$root/cert/oauth-keys.conf <>$root/conf/auth.conf <>$root/conf/modules.conf <>$root/conf/locauth$sslsuffix.conf < 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&)> 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 failableResult(const list& 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&)>(http::proxy(uri, "", "", "", "", p)); + return lambda&)>(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& impls, const SSLConf& sslc) : name(name), impls(impls), sslc(sslc) { + implProxy(const value& name, const list& impls, const SSLConf& sslc, const int timeout) : name(name), impls(impls), sslc(sslc), timeout(timeout) { } const value callImpl(const value& cname, const list& 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&)> px = lambda&)>(http::proxy(str(appuri), sslc.ca, sslc.cert, sslc.key, httpd::cookie(currentRequest), p)); + const lambda&)> px = lambda&)>(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&)> px = lambda&)>(http::proxy(uri, sslc.ca, sslc.cert, sslc.key, httpd::cookie(currentRequest), p)); + const lambda&)> px = lambda&)>(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&)> px = lambda&)>(http::proxy(uri, "", "", "", "", p)); + const lambda&)> px = lambda&)>(http::proxy(uri, "", "", "", "", timeout, p)); return px(aparams); } @@ -259,11 +271,12 @@ private: const value name; const list& impls; const SSLConf& sslc; + const int timeout; }; -const value mkimplProxy(const value& name, const list& impls, const SSLConf& sslc) { +const value mkimplProxy(const value& name, const list& impls, const SSLConf& sslc, const int timeout) { debug(name, "modeval::implProxy::impl"); - return lambda&)>(implProxy(name, impls, sslc)); + return lambda&)>(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& impls, const SSLConf& sslc, const gc_pool& p) { +const value mkrefProxy(const value& ref, const list& 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& 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 refProxies(const list& refs, const list& impls, const SSLConf& sslc, const gc_pool& p) { +const list refProxies(const list& refs, const list& 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& params) const { + if (currentRequest == NULL) + return v; + const ServerConf& sc = httpd::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&)>(userPropProxy(v)); if (n == "realm") return lambda&)>(realmPropProxy(v)); + if (n == "timeout") + return lambda&)>(timeoutPropProxy(v)); if (n == "email") return lambda&)>(envPropProxy("EMAIL", v)); if (n == "nickname") @@ -499,7 +528,7 @@ struct implementationFailure { } }; -const value evalComponent(const string& contribPath, const value& comp, const list& impls, const lambda&)> lifecycle, const SSLConf& sslc, const gc_pool& p) { +const value evalComponent(const string& contribPath, const value& comp, const list& impls, const lambda&)> lifecycle, const SSLConf& sslc, const int timeout, const gc_pool& p) { extern const failable&)> > evalImplementation(const string& cpath, const value& impl, const list& px, const lambda&)>& 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 rpx(refProxies(scdl::references(comp), impls, sslc, p)); + const list rpx(refProxies(scdl::references(comp), impls, sslc, timeout, p)); // Convert component properties to configured proxy lambdas const list 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 componentToImplementationAssoc(const list& c, const string& contribPath, const list& impls, const lambda&)> lifecycle, const SSLConf& sslc, const gc_pool& p) { +const list componentToImplementationAssoc(const list& c, const string& contribPath, const list& impls, const lambda&)> lifecycle, const SSLConf& sslc, const int timeout, const gc_pool& p) { if (isNil(c)) return c; return cons(mklist(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 > readComponents(const string& path) { } /** - * Get the components returned by a provider. + * Get the components returned by a contributor. */ -const failable > getComponents(const lambda&)>& provider, const string& name) { - const failable val = failableResult(provider(cons("get", mklist(mklist(name))))); +const failable > getComponents(const lambda&)>& contributor, const string& name) { + const failable val = failableResult(contributor(cons("get", mklist(mklist(name))))); if (!hasContent(val)) return mkfailure >(val); - const list c = assoc(value("content"), (list >)cdr(content(val))); + const list c = assoc(value("composite"), assoc(value("content"), (list >)cdr(car(content(val))))); + debug(c, "modeval::getComponents::comp"); if (isNil(c)) return mkfailure >(string("Could not get composite: ") + name); - const failable > x = writeXML(car(valuesToElements(mklist(mklist(cadr(c)))))); + const failable > x = writeXML(car(valuesToElements(mklist(mklist(c))))); if (!hasContent(x)) return mkfailure >(x); return scdl::components(readXML(content(x))); @@ -631,16 +661,16 @@ const list uriToComponentAssoc(const list& c) { /** * Configure the components declared in the deployed composite. */ -const failable confComponents(const string& contribPath, const string& composName, const value& provider, const string& vhost, const list& impls, const lambda&)> lifecycle, const SSLConf& sslc, const gc_pool& p) { +const failable confComponents(const string& contribPath, const string& composName, const value& contributor, const string& vhost, const list& impls, const lambda&)> 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 > fcomps = isNil(provider)? + const failable > fcomps = isNil(contributor)? readComponents(scdl::resourcePath(length(vhost) != 0? contribPath + vhost + "/" : contribPath, composName)) : - getComponents(provider, vhost); + getComponents(contributor, vhost); if (!hasContent(fcomps)) return mkfailure(fcomps); @@ -654,8 +684,8 @@ const failable confComponents(const string& contribPath, const string debug(flatten(svcs), "modeval::confComponents::svcs"); const list 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 get(const list& rpath, request_rec* r, const lambda fmt = assoc("format", args); @@ -735,6 +769,7 @@ const failable get(const list& rpath, request_rec* r, const lambda lc = mklist(mklist("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& rpath, const list< // Attempt to map a request targeting the main host to an actual file if (isNil(vpath)) { - const failable fnr = httpd::internalSubRequest(r->uri, r); + const failable 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 fvcompos = confComponents(sc.vhostc.contribPath, sc.vhostc.composName, sc.vhostc.provider, vname, reqc.impls, sc.lifecycle, sc.sslc, sc.p); + const failable 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 fvcompos = confComponents(sc.vhostc.contribPath, sc.vhostc.composName, sc.vhostc.provider, vname, reqc.impls, sc.lifecycle, sc.sslc, sc.p); + const failable 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& rpath, request_rec *r, const list(string("Couldn't find component implementation: ") + cadr(rpath)); return HTTP_NOT_FOUND; } + const lambda&)> l(cadr(impl)); // Handle HTTP method - const lambda&)> l(cadr(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); @@ -1227,6 +1261,61 @@ int handler(request_rec *r) { return handleRequest(reqc.rpath, r, sc.compos.impls); } +/** + * 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(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED); + return AUTH_DENIED; + } + + // Get the server configuration + const ServerConf& sc = httpd::serverConf(r, &mod_tuscany_eval); + if (isNil(sc.vhostc.authenticator)) { + mkfailure("SCA authenticator not configured"); + return AUTH_GENERAL_ERROR; + } + + // Retrieve the user's password hash + const list uid = pathValues(user); + const failable val = failableResult(sc.vhostc.authenticator(cons("get", mklist(uid)))); + if (!hasContent(val)) { + mkfailure(string("SCA authentication check user failed, user not found: ") + user); + return AUTH_USER_NOT_FOUND; + } + const value hval = content(val); + const list hcontent = isList(hval) && !isNil(hval) && isList(car(hval)) && !isNil(car(hval))? assoc(value("content"), cdr(car(hval))) : list(); + const list hassoc = isNil(hcontent)? list() : assoc(value("hash"), cdr(hcontent)); + if (isNil(hassoc)) { + mkfailure(string("SCA authentication check user failed, hash not found: ") + user); + return AUTH_USER_NOT_FOUND; + } + const string hash = cadr(hassoc); + if (length(hash) == 0) { + mkfailure(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(string("SCA authentication user password check failed: ") + user); + return AUTH_DENIED; + } + return AUTH_GRANTED; +} + /** * Cleanup callback, called when the server is stopped or restarted. */ @@ -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 compos = confComponents(sc.contribc.contribPath, sc.contribc.composName, value(), "", sc.compos.impls, sc.lifecycle, sc.sslc, sc.p); + const failable 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; @@ -1325,29 +1415,50 @@ int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, return postConfigMerge(sc, s->next); } +/** + * 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 > 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 impl(assoctree(sc.vhostc.contributorName, sc.compos.impls)); + if (isNil(impl)) { + mkfailure(string("Couldn't find contributor component implementation: ") + sc.vhostc.contributorName); + failureExitChild(); + } + sc.vhostc.contributor = cadr(impl); + } + + // Get the vhost authenticator component implementation lambda + if (length(sc.vhostc.authenticatorName) != 0) { + const list impl(assoctree(sc.vhostc.authenticatorName, sc.compos.impls)); + if (isNil(impl)) { + mkfailure(string("Couldn't find authenticator component implementation: ") + sc.vhostc.authenticatorName); + failureExitChild(); + } + sc.vhostc.authenticator = cadr(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(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(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(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(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 -- cgit v1.2.3