summaryrefslogtreecommitdiffstats
path: root/sandbox/sebastien/cpp/apr-2/modules/oauth
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/sebastien/cpp/apr-2/modules/oauth')
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/Makefile.am42
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/index.html58
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/index.html116
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/mixed.html211
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/logout/index.html33
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/public/index.html27
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth1.cpp580
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth2.cpp432
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/oauth-conf59
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/oauth-memcached-conf32
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/oauth.composite44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/oauth1-appkey-conf36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/oauth2-appkey-conf36
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/start-mixed-test67
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/start-test54
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/modules/oauth/stop-test24
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/oauth/user-info.scm36
17 files changed, 1887 insertions, 0 deletions
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/Makefile.am b/sandbox/sebastien/cpp/apr-2/modules/oauth/Makefile.am
new file mode 100644
index 0000000000..6c0cd2bc57
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/Makefile.am
@@ -0,0 +1,42 @@
+# 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.
+
+if WANT_OAUTH
+
+INCLUDES = -I${HTTPD_INCLUDE} -I${LIBOAUTH_INCLUDE}
+
+dist_mod_SCRIPTS = oauth-conf oauth-memcached-conf oauth1-appkey-conf oauth2-appkey-conf
+moddir=$(prefix)/modules/oauth
+
+mod_LTLIBRARIES = libmod_tuscany_oauth1.la libmod_tuscany_oauth2.la
+noinst_DATA = libmod_tuscany_oauth1.so libmod_tuscany_oauth2.so
+
+libmod_tuscany_oauth1_la_SOURCES = mod-oauth1.cpp
+libmod_tuscany_oauth1_la_LDFLAGS = -L${LIBOAUTH_LIB} -R${LIBOAUTH_LIB} -loauth -lxml2 -lcurl -lmozjs
+libmod_tuscany_oauth1.so:
+ ln -s .libs/libmod_tuscany_oauth1.so
+
+libmod_tuscany_oauth2_la_SOURCES = mod-oauth2.cpp
+libmod_tuscany_oauth2_la_LDFLAGS = -lxml2 -lcurl -lmozjs
+libmod_tuscany_oauth2.so:
+ ln -s .libs/libmod_tuscany_oauth2.so
+
+EXTRA_DIST = oauth.composite user-info.scm htdocs/index.html htdocs/login/index.html htdocs/logout/index.html htdocs/public/index.html
+
+dist_noinst_SCRIPTS = start-test stop-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/index.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/index.html
new file mode 100644
index 0000000000..7d26567214
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/index.html
@@ -0,0 +1,58 @@
+<!--
+ 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.
+-->
+
+<html>
+<head>
+<script type="text/javascript" src="/component.js"></script>
+<script type="text/javascript">
+var protected = sca.component("Protected");
+var userInfo = sca.defun(sca.reference(protected, "userInfo"), "getuser", "getemail", "getnickname", "getfullname", "getfirstname", "getlastname", "getrealm");
+var user = userInfo.getuser();
+var email = userInfo.apply("getemail");
+var nickname = userInfo.apply("getnickname");
+var fullname = userInfo.apply("getfullname");
+var firstname = userInfo.apply("getfirstname");
+var lastname = userInfo.apply("getlastname");
+var realm = userInfo.apply("getrealm");
+</script>
+</head>
+<body>
+<h1>Protected area - It works!</h1>
+<p>The following info is returned by a JSONRPC service:</p>
+<div>User: <span id="user"></span></div>
+<div>Email: <span id="email"></span></div>
+<div>Nickname: <span id="nickname"></span></div>
+<div>Fullname: <span id="fullname"></span></div>
+<div>Firstname: <span id="firstname"></span></div>
+<div>Lastname: <span id="lastname"></span></div>
+<div>Realm: <span id="realm"></span></div>
+<script type="text/javascript">
+document.getElementById('user').innerHTML=user;
+document.getElementById('email').innerHTML=email;
+document.getElementById('nickname').innerHTML=nickname;
+document.getElementById('fullname').innerHTML=fullname;
+document.getElementById('firstname').innerHTML=firstname;
+document.getElementById('lastname').innerHTML=lastname;
+document.getElementById('realm').innerHTML=realm;
+</script>
+<p><a href="info">User info</a></p>
+<p><a href="login">Sign in</a></p>
+<p><a href="logout">Sign out</a></p>
+<p><a href="public">Public area</a></p>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/index.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/index.html
new file mode 100644
index 0000000000..c41c334b76
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/index.html
@@ -0,0 +1,116 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in with an OAuth provider</h1>
+
+<script type="text/javascript">
+function queryParams() {
+ qp = new Array();
+ qs = window.location.search.substring(1).split('&');
+ for (i = 0; i < qs.length; i++) {
+ e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+}
+
+function oauthReferrer() {
+ r = queryParams()['openauth_referrer'];
+ if (typeof(r) == 'undefined')
+ return r;
+ q = r.indexOf('?');
+ if (q > 0)
+ return r.substring(0, q);
+ return r;
+}
+
+if (typeof(oauthReferrer()) == 'undefined') {
+ document.location = '/';
+}
+
+function submitSignin2(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signin2.mod_oauth2_authorize.value = parms[0];
+ document.signin2.mod_oauth2_access_token.value = parms[1];
+ document.signin2.mod_oauth2_client_id.value = parms[2];
+ document.signin2.mod_oauth2_info.value = parms[3];
+ document.signin2.action = oauthReferrer();
+ document.signin2.submit();
+}
+
+function withFacebook() {
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'facebook.com', 'https://graph.facebook.com/me'];
+ return parms;
+}
+
+function withGithub() {
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'github.com', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitSignin1(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signin1.mod_oauth1_request_token.value = parms[0];
+ document.signin1.mod_oauth1_authorize.value = parms[1];
+ document.signin1.mod_oauth1_access_token.value = parms[2];
+ document.signin1.mod_oauth1_client_id.value = parms[3];
+ document.signin1.mod_oauth1_info.value = parms[4];
+ document.signin1.action = oauthReferrer();
+ document.signin1.submit();
+}
+
+function withLinkedin() {
+ var parms = ['https://api.linkedin.com/uas/oauth/requestToken', 'https://www.linkedin.com/uas/oauth/authorize', 'https://api.linkedin.com/uas/oauth/accessToken', 'linkedin.com', 'https://api.linkedin.com/v1/people/~:(id,first-name,last-name,public-profile-url)'];
+ return parms;
+}
+
+function withTwitter() {
+ var parms = ['https://api.twitter.com/oauth/request_token', 'https://api.twitter.com/oauth/authorize', 'https://api.twitter.com/oauth/access_token', 'twitter.com', 'https://api.twitter.com/1/statuses/user_timeline.json'];
+ return parms;
+}
+</script>
+
+<form name="fields">
+<p>Sign in with your Facebook account<br/><input type="button" onclick="submitSignin2(withFacebook)" value="Sign in"/></p>
+<p>Sign in with your Github account<br/><input type="button" onclick="submitSignin2(withGithub)" value="Sign in"/></p>
+<p>Sign in with your Linkedin account<br/><input type="button" onclick="submitSignin1(withLinkedin)" value="Sign in"/></p>
+<p>Sign in with your Twitter account<br/><input type="button" onclick="submitSignin1(withTwitter)" value="Sign in"/></p>
+</form>
+
+<form name="signin2" action="/" method="GET">
+<input type="hidden" name="mod_oauth2_authorize" value=""/>
+<input type="hidden" name="mod_oauth2_access_token" value=""/>
+<input type="hidden" name="mod_oauth2_client_id" value=""/>
+<input type="hidden" name="mod_oauth2_info" value=""/>
+<input type="hidden" name="mod_oauth2_step" value="authorize"/>
+</form>
+
+<form name="signin1" action="/" method="GET">
+<input type="hidden" name="mod_oauth1_request_token" value=""/>
+<input type="hidden" name="mod_oauth1_authorize" value=""/>
+<input type="hidden" name="mod_oauth1_access_token" value=""/>
+<input type="hidden" name="mod_oauth1_client_id" value=""/>
+<input type="hidden" name="mod_oauth1_info" value=""/>
+<input type="hidden" name="mod_oauth1_step" value="authorize"/>
+</form>
+
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/mixed.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/mixed.html
new file mode 100644
index 0000000000..54673e01ee
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/login/mixed.html
@@ -0,0 +1,211 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>Sign in with a Form, an OpenID provider or an OAuth provider</h1>
+
+<script type="text/javascript">
+function submitFormSignin() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.formSignin.httpd_location.value = '/';
+ document.formSignin.submit();
+}
+
+function queryParams() {
+ qp = new Array();
+ qs = window.location.search.substring(1).split('&');
+ for (i = 0; i < qs.length; i++) {
+ e = qs[i].indexOf('=');
+ if (e > 0)
+ qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
+ }
+ return qp;
+}
+
+function openauthReferrer() {
+ r = queryParams()['openauth_referrer'];
+ if (typeof(r) == 'undefined')
+ return r;
+ q = r.indexOf('?');
+ if (q > 0)
+ return r.substring(0, q);
+ return r;
+}
+
+if (typeof(openauthReferrer()) == 'undefined') {
+ document.location = '/';
+}
+
+function submitOpenIDSignin(w) {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.openIDSignin.openid_identifier.value = w();
+ document.openIDSignin.action = openauthReferrer();
+ document.openIDSignin.submit();
+}
+
+function withGoogle() {
+ return 'https://www.google.com/accounts/o8/id';
+}
+
+function withYahoo() {
+ return 'https://me.yahoo.com/';
+}
+
+function withMyOpenID() {
+ return 'http://www.myopenid.com/xrds';
+}
+
+function withVerisign() {
+ return 'https://pip.verisignlabs.com/';
+}
+
+function withMySpace() {
+ return 'https://api.myspace.com/openid';
+}
+
+function withGoogleApps() {
+ return 'https://www.google.com/accounts/o8/site-xrds?ns=2&hd=' + document.fields.domain.value;
+}
+
+function withLivejournal() {
+ return 'http://' + document.fields.ljuser.value + '.livejournal.com';
+}
+
+function withBlogspot() {
+ return 'http://' + document.fields.bsuser.value + '.blogspot.com';
+}
+
+function withBlogger() {
+ return 'http://' + document.fields.bguser.value + '.blogger.com';
+}
+
+function withXRDSEndpoint() {
+ return document.fields.endpoint.value;
+}
+
+function submitOAuth2Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth2Signin.mod_oauth2_authorize.value = parms[0];
+ document.oauth2Signin.mod_oauth2_access_token.value = parms[1];
+ document.oauth2Signin.mod_oauth2_client_id.value = parms[2];
+ document.oauth2Signin.mod_oauth2_info.value = parms[3];
+ document.oauth2Signin.action = openauthReferrer();
+ document.oauth2Signin.submit();
+}
+
+function withFacebook() {
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'facebook.com', 'https://graph.facebook.com/me'];
+ return parms;
+}
+
+function withGithub() {
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'github.com', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitOAuth1Signin(w) {
+ parms = w();
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.oauth1Signin.mod_oauth1_request_token.value = parms[0];
+ document.oauth1Signin.mod_oauth1_authorize.value = parms[1];
+ document.oauth1Signin.mod_oauth1_access_token.value = parms[2];
+ document.oauth1Signin.mod_oauth1_client_id.value = parms[3];
+ document.oauth1Signin.mod_oauth1_info.value = parms[4];
+ document.oauth1Signin.action = openauthReferrer();
+ document.oauth1Signin.submit();
+}
+
+function withLinkedin() {
+ var parms = ['https://api.linkedin.com/uas/oauth/requestToken', 'https://www.linkedin.com/uas/oauth/authorize', 'https://api.linkedin.com/uas/oauth/accessToken', 'linkedin.com', 'https://api.linkedin.com/v1/people/~:(id,first-name,last-name,public-profile-url)'];
+ return parms;
+}
+
+function withTwitter() {
+ var parms = ['https://api.twitter.com/oauth/request_token', 'https://api.twitter.com/oauth/authorize', 'https://api.twitter.com/oauth/access_token', 'twitter.com', 'https://api.twitter.com/1/statuses/user_timeline.json'];
+ return parms;
+}
+</script>
+
+<form name="formSignin" method="POST" action="/login/dologin">
+<p>Sign in with your user id and password<br/>
+<table border="0">
+<tr><td>Username:</td><td><input type="text" name="httpd_username" value=""/></td></tr>
+<tr><td>Password:</td><td><input type="password" name="httpd_password" value=""/></td></tr>
+<tr><td><input type="button" onclick="submitFormSignin()" value="Sign in"/></td><td></td></tr>
+</table>
+</p>
+<input type="hidden" name="httpd_location" value="/"/>
+</form>
+
+<form name="fields">
+<p>Sign in with your Google account<br/><input type="button" onclick="submitOpenIDSignin(withGoogle)" value="Sign in"/></p>
+<p>Sign in with your Yahoo account<br/><input type="button" onclick="submitOpenIDSignin(withYahoo)" value="Sign in"/></p>
+<p>Sign in with your MyOpenID account<br/><input type="button" onclick="submitOpenIDSignin(withMyOpenID)" value="Sign in"/></p>
+<p>Sign in with your Verisign account<br/><input type="button" onclick="submitOpenIDSignin(withVerisign)" value="Sign in"/></p>
+<p>Sign in with your MySpace account<br/><input type="button" onclick="submitOpenIDSignin(withMySpace)" value="Sign in"/></p>
+
+<p>Sign in with a Google apps domain<br/>
+<input type="text" size="20" name="domain" value="example.com"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withGoogleApps)" value="Sign in"/></p>
+
+<p>Sign in with your Livejournal account<br/>
+<input type="text" size="10" name="ljuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withLivejournal)" value="Sign in"/></p>
+
+<p>Sign in with your Blogspot account<br/>
+<input type="text" size="10" name="bsuser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogspot)" value="Sign in"/></p>
+
+<p>Sign in with your Blogger account<br/>
+<input type="text" size="10" name="bguser" value=""/><br/>
+<input type="button" onclick="submitOpenIDSignin(withBlogger)" value="Sign in"/></p>
+
+<p>Sign in with an OpenID endpoint<br/>
+<input type="text" size="50" name="endpoint" value="https://www.google.com/accounts/o8/id"/><br/>
+<input type="button" onclick="submitOpenIDSignin(withXRDSEndpoint)" value="Sign in"/></p>
+
+<p>Sign in with your Facebook account<br/><input type="button" onclick="submitOAuth2Signin(withFacebook)" value="Sign in"/></p>
+<p>Sign in with your Github account<br/><input type="button" onclick="submitOAuth2Signin(withGithub)" value="Sign in"/></p>
+
+<p>Sign in with your Linkedin account<br/><input type="button" onclick="submitOAuth1Signin(withLinkedin)" value="Sign in"/></p>
+<p>Sign in with your Twitter account<br/><input type="button" onclick="submitOAuth1Signin(withTwitter)" value="Sign in"/></p>
+</form>
+
+<form name="openIDSignin" action="/" method="GET">
+<input type="hidden" name="openid_identifier" value=""/>
+</form>
+
+<form name="oauth2Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth2_authorize" value=""/>
+<input type="hidden" name="mod_oauth2_access_token" value=""/>
+<input type="hidden" name="mod_oauth2_client_id" value=""/>
+<input type="hidden" name="mod_oauth2_info" value=""/>
+<input type="hidden" name="mod_oauth2_step" value="authorize"/>
+</form>
+
+<form name="oauth1Signin" action="/" method="GET">
+<input type="hidden" name="mod_oauth1_request_token" value=""/>
+<input type="hidden" name="mod_oauth1_authorize" value=""/>
+<input type="hidden" name="mod_oauth1_access_token" value=""/>
+<input type="hidden" name="mod_oauth1_client_id" value=""/>
+<input type="hidden" name="mod_oauth1_info" value=""/>
+<input type="hidden" name="mod_oauth1_step" value="authorize"/>
+</form>
+
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/logout/index.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/logout/index.html
new file mode 100644
index 0000000000..02a92d1b31
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/logout/index.html
@@ -0,0 +1,33 @@
+<!--
+ 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.
+-->
+
+<html><body>
+<h1>Sign out</h1>
+
+<form name="signout" action="/login" method="GET">
+<script type="text/javascript">
+function submitSignout() {
+ document.cookie = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';path=/;secure=TRUE';
+ document.signout.submit();
+ return true;
+}
+</script>
+<input type="button" onclick="submitSignout()" value="Sign out"/>
+</form>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/public/index.html b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/public/index.html
new file mode 100644
index 0000000000..af2cd7ca19
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/htdocs/public/index.html
@@ -0,0 +1,27 @@
+<!--
+ 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.
+-->
+
+<html>
+<body>
+<h1>Unprotected area - It works!</h1>
+<p><a href="/info">User info</a></p>
+<p><a href="/login">Sign in</a></p>
+<p><a href="/logout">Sign out</a></p>
+<p><a href="/">Protected area</a></p>
+</body></html>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth1.cpp b/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth1.cpp
new file mode 100644
index 0000000000..0f190127db
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth1.cpp
@@ -0,0 +1,580 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module for OAuth 1.0 authentication.
+ */
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+extern "C" {
+#include <oauth.h>
+}
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../json/json.hpp"
+#include "../http/httpd.hpp"
+#include "../http/http.hpp"
+#include "../http/openauth.hpp"
+#include "../../components/cache/memcache.hpp"
+
+extern "C" {
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_oauth1;
+}
+
+namespace tuscany {
+namespace oauth1 {
+
+/**
+ * Server configuration.
+ */
+class ServerConf {
+public:
+ ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) {
+ }
+
+ const gc_pool p;
+ server_rec* server;
+ string ca;
+ string cert;
+ string key;
+ list<list<value> > appkeys;
+ list<string> mcaddrs;
+ memcache::MemCached mc;
+ http::CURLSession cs;
+};
+
+/**
+ * Directory configuration.
+ */
+class DirConf {
+public:
+ DirConf(apr_pool_t* p, char* d) : p(p), dir(d), enabled(false), login("") {
+ }
+
+ const gc_pool p;
+ const char* dir;
+ bool enabled;
+ string login;
+};
+
+/**
+ * Return the user info for a session.
+ */
+const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) {
+ return memcache::get(mklist<value>("tuscanyOpenAuth", sid), mc);
+}
+
+/**
+ * Handle an authenticated request.
+ */
+const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
+ debug(info, "modoauth1::authenticated::info");
+
+ // Store user info in the request
+ const list<value> realm = assoc<value>("realm", info);
+ if (isNil(realm) || isNil(cdr(realm)))
+ return mkfailure<int>("Couldn't retrieve realm");
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm))));
+
+ const list<value> id = assoc<value>("id", info);
+ if (isNil(id) || isNil(cdr(id)))
+ return mkfailure<int>("Couldn't retrieve user id");
+ r->user = apr_pstrdup(r->pool, c_str(cadr(id)));
+
+ const list<value> email = assoc<value>("email", info);
+ if (!isNil(email) && !isNil(cdr(email)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "EMAIL"), apr_pstrdup(r->pool, c_str(cadr(email))));
+
+ const list<value> screenname = assoc<value>("screen_name", info);
+ if (!isNil(screenname) && !isNil(cdr(screenname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "NICKNAME"), apr_pstrdup(r->pool, c_str(cadr(screenname))));
+
+ const list<value> name = assoc<value>("name", info);
+ if (!isNil(name) && !isNil(cdr(name)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FULLNAME"), apr_pstrdup(r->pool, c_str(cadr(name))));
+
+ const list<value> firstname = assoc<value>("first-name", info);
+ if (!isNil(firstname) && !isNil(cdr(firstname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FIRSTNAME"), apr_pstrdup(r->pool, c_str(cadr(firstname))));
+
+ const list<value> lastname = assoc<value>("last-name", info);
+ if (!isNil(lastname) && !isNil(cdr(lastname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "LASTNAME"), apr_pstrdup(r->pool, c_str(cadr(lastname))));
+ return OK;
+}
+
+/**
+ * Convert a query string containing oauth args to an authorization header.
+ */
+const string header(const string& qs, const string& redir, const string& verif) {
+ const list<list<value> > args = httpd::queryArgs(qs);
+ ostringstream hdr;
+ hdr << "Authorization: OAuth "
+ << "oauth_nonce=\"" << string(cadr(assoc<value>("oauth_nonce", args))) << "\", ";
+
+ if (length(redir) != 0)
+ hdr << "oauth_callback=\"" << httpd::escape(redir) << "\", ";
+
+ hdr << "oauth_signature_method=\"" << string(cadr(assoc<value>("oauth_signature_method", args))) << "\", "
+ << "oauth_timestamp=\"" << string(cadr(assoc<value>("oauth_timestamp", args))) << "\", "
+ << "oauth_consumer_key=\"" << string(cadr(assoc<value>("oauth_consumer_key", args))) << "\", ";
+
+ const list<value> atok = assoc<value>("oauth_token", args);
+ if (!isNil(atok) && !isNil(cdr(atok)))
+ hdr << "oauth_token=\"" << string(cadr(atok)) << "\", ";
+
+ if (length(verif) != 0)
+ hdr << "oauth_verifier=\"" << verif << "\", ";
+
+ hdr << "oauth_signature=\"" << string(cadr(assoc<value>("oauth_signature", args))) << "\", "
+ << "oauth_version=\"" << string(cadr(assoc<value>("oauth_version", args))) << "\"";
+ debug(str(hdr), "modoauth1::authheader");
+ return str(hdr);
+}
+
+
+/**
+ * Sign a request.
+ */
+const list<string> sign(const string& verb, const string& uri, const list<value> appkey, const string& tok, const string& sec) {
+ char* qs = NULL;
+ char* suri = oauth_sign_url2(c_str(uri), &qs, OA_HMAC, c_str(verb), c_str(car(appkey)), c_str(cadr(appkey)), length(tok) != 0? c_str(tok) : NULL, length(sec) != 0? c_str(sec) : NULL);
+ const list<string> res = mklist<string>(suri, qs);
+ free(suri);
+ free(qs);
+ return res;
+}
+
+/**
+ * Handle an authorize request.
+ */
+const failable<int> authorize(const list<list<value> >& args, request_rec* r, const ServerConf& sc) {
+ // Extract authorize, access_token, client ID and info URIs
+ const list<value> req = assoc<value>("mod_oauth1_request_token", args);
+ if (isNil(req) || isNil(cdr(req)))
+ return mkfailure<int>("Missing mod_oauth1_request_token parameter");
+ const list<value> auth = assoc<value>("mod_oauth1_authorize", args);
+ if (isNil(auth) || isNil(cdr(auth)))
+ return mkfailure<int>("Missing mod_oauth1_authorize parameter");
+ const list<value> tok = assoc<value>("mod_oauth1_access_token", args);
+ if (isNil(tok) || isNil(cdr(tok)))
+ return mkfailure<int>("Missing mod_oauth1_access_token parameter");
+ const list<value> cid = assoc<value>("mod_oauth1_client_id", args);
+ if (isNil(cid) || isNil(cdr(cid)))
+ return mkfailure<int>("Missing mod_oauth1_client_id parameter");
+ const list<value> info = assoc<value>("mod_oauth1_info", args);
+ if (isNil(info) || isNil(cdr(info)))
+ return mkfailure<int>("Missing mod_oauth1_info parameter");
+
+ // Build the redirect URI
+ const list<list<value> > redirargs = mklist<list<value> >(mklist<value>("mod_oauth1_step", "access_token"), tok, cid, info);
+ const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(redirargs);
+ debug(redir, "modoauth1::authorize::redir");
+
+ // Lookup client app configuration
+ const list<value> app = assoc<value>(cadr(cid), sc.appkeys);
+ if (isNil(app) || isNil(cdr(app)))
+ return mkfailure<int>(string("client id not found: ") + cadr(cid));
+ list<value> appkey = cadr(app);
+
+ // Build and sign the request token URI
+ const string requri = httpd::unescape(cadr(req)) + string("&") + httpd::queryString(mklist<list<value> >(mklist<value>("oauth_callback", httpd::escape(redir))));
+ const list<string> srequri = sign("POST", requri, appkey, "", "");
+ debug(srequri, "modoauth1::authorize::srequri");
+
+ // Put the args into an oauth header
+ const string reqhdr = header(cadr(srequri), redir, "");
+
+ // Send the request token request
+ char* pres = oauth_http_post2(c_str(car(srequri)), "", c_str(reqhdr));
+ if (pres == NULL)
+ return mkfailure<int>("Couldn't send request token request");
+ const string res(pres);
+ free(pres);
+ debug(res, "modoauth1::authorize::res");
+ const list<list<value> > resargs = httpd::queryArgs(res);
+
+ // Retrieve the request token
+ const list<value> conf = assoc<value>("oauth_callback_confirmed", resargs);
+ if (isNil(conf) || isNil(cdr(conf)) || cadr(conf) != "true")
+ return mkfailure<int>("Couldn't confirm oauth_callback");
+ const list<value> tv = assoc<value>("oauth_token", resargs);
+ if (isNil(tv) || isNil(cdr(tv)))
+ return mkfailure<int>("Couldn't retrieve oauth_token");
+ const list<value> sv = assoc<value>("oauth_token_secret", resargs);
+ if (isNil(sv) || isNil(cdr(sv)))
+ return mkfailure<int>("Couldn't retrieve oauth_token_secret");
+
+ // Store the request token in memcached
+ const failable<bool> prc = memcache::put(mklist<value>("tuscanyOAuth1Token", cadr(tv)), cadr(sv), sc.mc);
+ if (!hasContent(prc))
+ return mkfailure<int>(reason(prc));
+
+ // Redirect to the authorize URI
+ const string authuri = httpd::unescape(cadr(auth)) + string("?") + httpd::queryString(mklist<list<value> >(tv));
+ debug(authuri, "modoauth1::authorize::authuri");
+ return httpd::externalRedirect(authuri, r);
+}
+
+/**
+ * Extract user info from a profile/info response.
+ * TODO This currently only works for Twitter, Foursquare and LinkedIn.
+ * User profile parsing needs to be made configurable.
+ */
+const failable<list<value> > profileUserInfo(const value& cid, const string& info) {
+ string b = substr(info, 0, 1);
+ if (b == "[") {
+ // Twitter JSON profile
+ js::JSContext cx;
+ const list<value> infov(json::jsonValues(content(json::readJSON(mklist<string>(info), cx))));
+ if (isNil(infov))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ debug(infov, "modoauth1::access_token::info");
+ const list<value> uv = assoc<value>("user", car(infov));
+ debug(uv, "modoauth1::access_token::userInfo");
+ if (isNil(uv) || isNil(cdr(uv)))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ const list<value> iv = cdr(uv);
+ return cons<value>(mklist<value>("realm", cid), iv);
+ }
+ if (b == "{") {
+ // Foursquare JSON profile
+ js::JSContext cx;
+ const list<value> infov(json::jsonValues(content(json::readJSON(mklist<string>(info), cx))));
+ if (isNil(infov))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ debug(infov, "modoauth1::access_token::info");
+ const list<value> uv = assoc<value>("user", infov);
+ debug(uv, "modoauth1::access_token::userInfo");
+ if (isNil(uv) || isNil(cdr(uv)))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ const list<value> iv = cdr(uv);
+ return cons<value>(mklist<value>("realm", cid), iv);
+ }
+ if (b == "<") {
+ // XML profile
+ const list<value> infov = elementsToValues(readXML(mklist<string>(info)));
+ if (isNil(infov))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ debug(infov, "modoauth1::access_token::info");
+ const list<value> pv = car(infov);
+ debug(pv, "modoauth1::access_token::userInfo");
+ if (isNil(pv) || isNil(cdr(pv)))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ const list<value> iv = cdr(pv);
+ return cons<value>(mklist<value>("realm", cid), iv);
+ }
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+}
+
+/**
+ * Handle an access_token request.
+ */
+const failable<int> access_token(const list<list<value> >& args, request_rec* r, const ServerConf& sc) {
+ // Extract access_token URI, client ID and verification code
+ const list<value> tok = assoc<value>("mod_oauth1_access_token", args);
+ if (isNil(tok) || isNil(cdr(tok)))
+ return mkfailure<int>("Missing mod_oauth1_access_token parameter");
+ const list<value> cid = assoc<value>("mod_oauth1_client_id", args);
+ if (isNil(cid) || isNil(cdr(cid)))
+ return mkfailure<int>("Missing mod_oauth1_client_id parameter");
+ const list<value> info = assoc<value>("mod_oauth1_info", args);
+ if (isNil(info) || isNil(cdr(info)))
+ return mkfailure<int>("Missing mod_oauth1_info parameter");
+ const list<value> tv = assoc<value>("oauth_token", args);
+ if (isNil(tv) || isNil(cdr(tv)))
+ return mkfailure<int>("Missing oauth_token parameter");
+ const list<value> vv = assoc<value>("oauth_verifier", args);
+ if (isNil(vv) || isNil(cdr(vv)))
+ return mkfailure<int>("Missing oauth_verifier parameter");
+
+ // Lookup client app configuration
+ const list<value> app = assoc<value>(cadr(cid), sc.appkeys);
+ if (isNil(app) || isNil(cdr(app)))
+ return mkfailure<int>(string("client id not found: ") + cadr(cid));
+ list<value> appkey = cadr(app);
+
+ // Retrieve the request token from memcached
+ const failable<value> sv = memcache::get(mklist<value>("tuscanyOAuth1Token", cadr(tv)), sc.mc);
+ if (!hasContent(sv))
+ return mkfailure<int>(reason(sv));
+
+ // Build and sign access token request URI
+ const string tokuri = httpd::unescape(cadr(tok)) + string("?") + httpd::queryString(mklist<list<value> >(vv));
+ const list<string> stokuri = sign("POST", tokuri, appkey, cadr(tv), content(sv));
+ debug(stokuri, "modoauth1::access_token::stokuri");
+
+ // Put the args into an oauth header
+ string tokhdr = header(cadr(stokuri), "", cadr(vv));
+
+ // Send the access token request
+ char* ptokres = oauth_http_post2(c_str(car(stokuri)), "", c_str(tokhdr));
+ if (ptokres == NULL)
+ return mkfailure<int>("Couldn't post access_token request");
+ const string tokres(ptokres);
+ free(ptokres);
+ debug(tokres, "modoauth1::access_token::res");
+ const list<list<value> > tokresargs = httpd::queryArgs(tokres);
+
+ // Retrieve the access token
+ const list<value> atv = assoc<value>("oauth_token", tokresargs);
+ if (isNil(atv) || isNil(cdr(atv)))
+ return mkfailure<int>("Couldn't retrieve oauth_token");
+ const list<value> asv = assoc<value>("oauth_token_secret", tokresargs);
+ if (isNil(asv) || isNil(cdr(asv)))
+ return mkfailure<int>("Couldn't retrieve oauth_token_secret");
+ debug(atv, "modoauth1::access_token::token");
+
+ // Build and sign user profile request URI
+ const string profuri = httpd::unescape(cadr(info));
+ const list<string> sprofuri = sign("GET", profuri, appkey, cadr(atv), cadr(asv));
+ debug(sprofuri, "modoauth1::access_token::sprofuri");
+
+ // Put the args into an oauth header
+ string profhdr = header(cadr(sprofuri), "", "");
+
+ // Send the user profile request
+ char* pprofres = oauth_http_get2(c_str(car(sprofuri)), NULL, c_str(profhdr));
+ if (pprofres == NULL)
+ return mkfailure<int>("Couldn't get user info");
+ const string profres(pprofres);
+ free(pprofres);
+ debug(profres, "modoauth1::access_token::profres");
+
+ // Retrieve the user info from the profile
+ const failable<list<value> > iv = profileUserInfo(cadr(cid), profres);
+ if (!hasContent(iv))
+ return mkfailure<int>(reason(iv));
+
+ // Store user info in memcached keyed by session ID
+ const value sid = string("OAuth1_") + mkrand();
+ const failable<bool> prc = memcache::put(mklist<value>("tuscanyOpenAuth", sid), content(iv), sc.mc);
+ if (!hasContent(prc))
+ return mkfailure<int>(reason(prc));
+
+ // Send session ID to the client in a cookie
+ apr_table_set(r->err_headers_out, "Set-Cookie", c_str(openauth::cookie(sid)));
+ return httpd::externalRedirect(httpd::url(r->uri, r), r);
+}
+
+/**
+ * Check user authentication.
+ */
+static int checkAuthn(request_rec *r) {
+ // Decline if we're not enabled or AuthType is not set to Open
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth1);
+ if (!dc.enabled)
+ return DECLINED;
+ const char* atype = ap_auth_type(r);
+ if (atype == NULL || strcasecmp(atype, "Open"))
+ return DECLINED;
+
+ gc_scoped_pool pool(r->pool);
+ httpdDebugRequest(r, "modoauth1::checkAuthn::input");
+ const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth1);
+
+ // Get session id from the request
+ const maybe<string> sid = openauth::sessionID(r);
+ if (hasContent(sid)) {
+ // Decline if the session id was not created by this module
+ if (substr(content(sid), 0, 7) != "OAuth1_")
+ return DECLINED;
+
+ // If we're authenticated store the user info in the request
+ const failable<value> info = userInfo(content(sid), sc.mc);
+ if (hasContent(info)) {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authenticated(content(info), r));
+ }
+ }
+
+ // Get the request args
+ const list<list<value> > args = httpd::queryArgs(r);
+
+ // Decline if the request is for another authentication provider
+ if (!isNil(assoc<value>("openid_identifier", args)))
+ return DECLINED;
+ if (!isNil(assoc<value>("mod_oauth2_step", args)))
+ return DECLINED;
+
+ // Determine the OAuth protocol flow step, conveniently passed
+ // around in a request arg
+ const list<value> sl = assoc<value>("mod_oauth1_step", args);
+ const value step = !isNil(sl) && !isNil(cdr(sl))? cadr(sl) : "";
+
+ // Handle OAuth authorize request step
+ if (step == "authorize") {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authorize(args, r, sc));
+ }
+
+ // Handle OAuth access_token request step
+ if (step == "access_token") {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(access_token(args, r, sc));
+ }
+
+ // Redirect to the login page
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(openauth::login(dc.login, r));
+}
+
+/**
+ * Process the module configuration.
+ */
+int postConfigMerge(ServerConf& mainsc, server_rec* s) {
+ if (s == NULL)
+ return OK;
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth1);
+ debug(httpd::serverName(s), "modoauth1::postConfigMerge::serverName");
+
+ // Merge configuration from main server
+ if (isNil(sc.appkeys))
+ sc.appkeys = mainsc.appkeys;
+ sc.mc = mainsc.mc;
+ sc.cs = mainsc.cs;
+
+ return postConfigMerge(mainsc, s->next);
+}
+
+int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth1);
+ debug(httpd::serverName(s), "modoauth1::postConfig::serverName");
+
+ // Merge server configurations
+ return postConfigMerge(sc, s);
+}
+
+/**
+ * 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_oauth1);
+ if(psc == NULL) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_oauth1 loading failed. Causing apache to stop loading." << endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+ ServerConf& sc = *psc;
+
+ // Connect to Memcached
+ if (isNil(sc.mcaddrs))
+ sc.mc = *(new (gc_new<memcache::MemCached>()) memcache::MemCached("localhost", 11211));
+ else
+ sc.mc = *(new (gc_new<memcache::MemCached>()) memcache::MemCached(sc.mcaddrs));
+
+ // Setup a CURL session
+ sc.cs = *(new (gc_new<http::CURLSession>()) http::CURLSession(sc.ca, sc.cert, sc.key));
+
+ // Merge the updated configuration into the virtual hosts
+ postConfigMerge(sc, s->next);
+}
+
+/**
+ * Configuration commands.
+ */
+const char* confAppKey(cmd_parms *cmd, unused void *c, const char *arg1, const char* arg2, const char* arg3) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.appkeys = cons<list<value> >(mklist<value>(arg1, mklist<value>(arg2, arg3)), sc.appkeys);
+ return NULL;
+}
+const char* confMemcached(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.mcaddrs = cons<string>(arg, sc.mcaddrs);
+ return NULL;
+}
+const char* confEnabled(cmd_parms *cmd, void *c, const int arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.enabled = (bool)arg;
+ return NULL;
+}
+const char* confLogin(cmd_parms *cmd, void *c, const char* arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.login = arg;
+ return NULL;
+}
+const char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.ca = arg;
+ return NULL;
+}
+const char* confCertFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.cert = arg;
+ return NULL;
+}
+const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth1);
+ sc.key = arg;
+ return NULL;
+}
+
+/**
+ * HTTP server module declaration.
+ */
+const command_rec commands[] = {
+ AP_INIT_TAKE3("AddAuthOAuth1AppKey", (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"),
+ AP_INIT_TAKE1("AuthOAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "OAuth 2.0 login page"),
+ AP_INIT_TAKE1("AuthOAuthSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "OAUth 2.0 SSL CA certificate file"),
+ AP_INIT_TAKE1("AuthOAuthSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "OAuth 2.0 SSL certificate file"),
+ AP_INIT_TAKE1("AuthOAuthSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "OAuth 2.0 SSL certificate key file"),
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
+};
+
+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);
+}
+
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_oauth1 = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::oauth1::DirConf>, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::oauth1::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::oauth1::commands, tuscany::oauth1::registerHooks
+};
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth2.cpp b/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth2.cpp
new file mode 100644
index 0000000000..b52967977e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/mod-oauth2.cpp
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * HTTPD module for OAuth 2.0 authentication.
+ */
+
+#include <sys/stat.h>
+
+#include "string.hpp"
+#include "stream.hpp"
+#include "list.hpp"
+#include "tree.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../http/httpd.hpp"
+#include "../http/http.hpp"
+#include "../http/openauth.hpp"
+#include "../../components/cache/memcache.hpp"
+
+extern "C" {
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_oauth2;
+}
+
+namespace tuscany {
+namespace oauth2 {
+
+/**
+ * Server configuration.
+ */
+class ServerConf {
+public:
+ ServerConf(apr_pool_t* p, server_rec* s) : p(p), server(s) {
+ }
+
+ const gc_pool p;
+ server_rec* server;
+ string ca;
+ string cert;
+ string key;
+ list<list<value> > appkeys;
+ list<string> mcaddrs;
+ memcache::MemCached mc;
+ http::CURLSession cs;
+};
+
+/**
+ * Directory configuration.
+ */
+class DirConf {
+public:
+ DirConf(apr_pool_t* p, char* d) : p(p), dir(d), enabled(false), login("") {
+ }
+
+ const gc_pool p;
+ const char* dir;
+ bool enabled;
+ string login;
+};
+
+/**
+ * Return the user info for a session.
+ */
+const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) {
+ return memcache::get(mklist<value>("tuscanyOpenAuth", sid), mc);
+}
+
+/**
+ * Handle an authenticated request.
+ */
+const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
+ debug(info, "modoauth2::authenticated::info");
+
+ // Store user info in the request
+ const list<value> realm = assoc<value>("realm", info);
+ if (isNil(realm) || isNil(cdr(realm)))
+ return mkfailure<int>("Couldn't retrieve realm");
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm))));
+
+ const list<value> id = assoc<value>("id", info);
+ if (isNil(id) || isNil(cdr(id)))
+ return mkfailure<int>("Couldn't retrieve user id");
+ r->user = apr_pstrdup(r->pool, c_str(cadr(id)));
+
+ const list<value> email = assoc<value>("email", info);
+ if (!isNil(email) && !isNil(cdr(email)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "EMAIL"), apr_pstrdup(r->pool, c_str(cadr(email))));
+
+ const list<value> fullname = assoc<value>("name", info);
+ if (!isNil(fullname) && !isNil(cdr(fullname))) {
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "NICKNAME"), apr_pstrdup(r->pool, c_str(cadr(fullname))));
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FULLNAME"), apr_pstrdup(r->pool, c_str(cadr(fullname))));
+ }
+
+ const list<value> firstname = assoc<value>("first_name", info);
+ if (!isNil(firstname) && !isNil(cdr(firstname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FIRSTNAME"), apr_pstrdup(r->pool, c_str(cadr(firstname))));
+
+ const list<value> lastname = assoc<value>("last_name", info);
+ if (!isNil(lastname) && !isNil(cdr(lastname)))
+ apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "LASTNAME"), apr_pstrdup(r->pool, c_str(cadr(lastname))));
+
+ return OK;
+}
+
+/**
+ * Handle an authorize request.
+ */
+const failable<int> authorize(const list<list<value> >& args, request_rec* r, const ServerConf& sc) {
+ // Extract authorize, access_token, client ID and info URIs
+ const list<value> auth = assoc<value>("mod_oauth2_authorize", args);
+ if (isNil(auth) || isNil(cdr(auth)))
+ return mkfailure<int>("Missing mod_oauth2_authorize parameter");
+ const list<value> tok = assoc<value>("mod_oauth2_access_token", args);
+ if (isNil(tok) || isNil(cdr(tok)))
+ return mkfailure<int>("Missing mod_oauth2_access_token parameter");
+ const list<value> cid = assoc<value>("mod_oauth2_client_id", args);
+ if (isNil(cid) || isNil(cdr(cid)))
+ return mkfailure<int>("Missing mod_oauth2_client_id parameter");
+ const list<value> info = assoc<value>("mod_oauth2_info", args);
+ if (isNil(info) || isNil(cdr(info)))
+ return mkfailure<int>("Missing mod_oauth2_info parameter");
+
+ // Build the redirect URI
+ const list<list<value> > rargs = mklist<list<value> >(mklist<value>("mod_oauth2_step", "access_token"), tok, cid, info);
+ const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(rargs);
+ debug(redir, "modoauth2::authorize::redir");
+
+ // Lookup client app configuration
+ const list<value> app = assoc<value>(cadr(cid), sc.appkeys);
+ if (isNil(app) || isNil(cdr(app)))
+ return mkfailure<int>(string("client id not found: ") + cadr(cid));
+ list<value> appkey = cadr(app);
+
+ // Redirect to the authorize URI
+ const list<list<value> > aargs = mklist<list<value> >(mklist<value>("client_id", car(appkey)), mklist<value>("scope", "email"), mklist<value>("redirect_uri", httpd::escape(redir)));
+ const string uri = httpd::unescape(cadr(auth)) + string("?") + httpd::queryString(aargs);
+ debug(uri, "modoauth2::authorize::uri");
+ return httpd::externalRedirect(uri, r);
+}
+
+/**
+ * Extract user info from a profile/info response.
+ * TODO This currently only works for Facebook and Gowalla.
+ * User profile parsing needs to be made configurable.
+ */
+const failable<list<value> > profileUserInfo(const value& cid, const list<value>& info) {
+ return cons<value>(mklist<value>("realm", cid), info);
+}
+
+/**
+ * Handle an access_token request.
+ */
+const failable<int> access_token(const list<list<value> >& args, request_rec* r, const ServerConf& sc) {
+ // Extract access_token URI, client ID and authorization code
+ const list<value> tok = assoc<value>("mod_oauth2_access_token", args);
+ if (isNil(tok) || isNil(cdr(tok)))
+ return mkfailure<int>("Missing mod_oauth2_access_token parameter");
+ const list<value> cid = assoc<value>("mod_oauth2_client_id", args);
+ if (isNil(cid) || isNil(cdr(cid)))
+ return mkfailure<int>("Missing mod_oauth2_client_id parameter");
+ const list<value> info = assoc<value>("mod_oauth2_info", args);
+ if (isNil(info) || isNil(cdr(info)))
+ return mkfailure<int>("Missing mod_oauth2_info parameter");
+ const list<value> code = assoc<value>("code", args);
+ if (isNil(code) || isNil(cdr(code)))
+ return mkfailure<int>("Missing code parameter");
+
+ // Lookup client app configuration
+ const list<value> app = assoc<value>(cadr(cid), sc.appkeys);
+ if (isNil(app) || isNil(cdr(app)))
+ return mkfailure<int>(string("client id not found: ") + cadr(cid));
+ list<value> appkey = cadr(app);
+
+ // Build the redirect URI
+ const list<list<value> > rargs = mklist<list<value> >(mklist<value>("mod_oauth2_step", "access_token"), tok, cid, info);
+ const string redir = httpd::url(r->uri, r) + string("?") + httpd::queryString(rargs);
+ debug(redir, "modoauth2::access_token::redir");
+
+ // Request access token
+ const list<list<value> > targs = mklist<list<value> >(mklist<value>("client_id", car(appkey)), mklist<value>("redirect_uri", httpd::escape(redir)), mklist<value>("client_secret", cadr(appkey)), code);
+ const string turi = httpd::unescape(cadr(tok)) + string("?") + httpd::queryString(targs);
+ debug(turi, "modoauth2::access_token::tokenuri");
+ const failable<value> tr = http::get(turi, sc.cs);
+ if (!hasContent(tr))
+ return mkfailure<int>(reason(tr));
+ debug(tr, "modoauth2::access_token::response");
+ const list<value> tv = assoc<value>("access_token", httpd::queryArgs(join("", convertValues<string>(content(tr)))));
+ if (isNil(tv) || isNil(cdr(tv)))
+ return mkfailure<int>("Couldn't retrieve access_token");
+ debug(tv, "modoauth2::access_token::token");
+
+ // Request user info
+ // TODO Make this step configurable
+ const list<list<value> > iargs = mklist<list<value> >(tv);
+ const string iuri = httpd::unescape(cadr(info)) + string("?") + httpd::queryString(iargs);
+ debug(iuri, "modoauth2::access_token::infouri");
+ const failable<value> profres = http::get(iuri, sc.cs);
+ if (!hasContent(profres))
+ return mkfailure<int>("Couldn't retrieve user info");
+ debug(content(profres), "modoauth2::access_token::info");
+
+ // Retrieve the user info from the profile
+ const failable<list<value> > iv = profileUserInfo(cadr(cid), content(profres));
+ if (!hasContent(iv))
+ return mkfailure<int>(reason(iv));
+
+ // Store user info in memcached keyed by session ID
+ const value sid = string("OAuth2_") + mkrand();
+ const failable<bool> prc = memcache::put(mklist<value>("tuscanyOpenAuth", sid), content(iv), sc.mc);
+ if (!hasContent(prc))
+ return mkfailure<int>(reason(prc));
+
+ // Send session ID to the client in a cookie
+ apr_table_set(r->err_headers_out, "Set-Cookie", c_str(openauth::cookie(sid)));
+ return httpd::externalRedirect(httpd::url(r->uri, r), r);
+}
+
+/**
+ * Check user authentication.
+ */
+static int checkAuthn(request_rec *r) {
+ // Decline if we're not enabled or AuthType is not set to Open
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth2);
+ if (!dc.enabled)
+ return DECLINED;
+ const char* atype = ap_auth_type(r);
+ if (atype == NULL || strcasecmp(atype, "Open"))
+ return DECLINED;
+
+ gc_scoped_pool pool(r->pool);
+ httpdDebugRequest(r, "modoauth2::checkAuthn::input");
+ const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth2);
+
+ // Get session id from the request
+ const maybe<string> sid = openauth::sessionID(r);
+ if (hasContent(sid)) {
+ // Decline if the session id was not created by this module
+ if (substr(content(sid), 0, 7) != "OAuth2_")
+ return DECLINED;
+
+ // If we're authenticated store the user info in the request
+ const failable<value> info = userInfo(content(sid), sc.mc);
+ if (hasContent(info)) {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authenticated(content(info), r));
+ }
+ }
+
+ // Get the request args
+ const list<list<value> > args = httpd::queryArgs(r);
+
+ // Decline if the request is for another authentication provider
+ if (!isNil(assoc<value>("openid_identifier", args)))
+ return DECLINED;
+ if (!isNil(assoc<value>("mod_oauth1_step", args)))
+ return DECLINED;
+
+ // Determine the OAuth protocol flow step, conveniently passed
+ // around in a request arg
+ const list<value> sl = assoc<value>("mod_oauth2_step", args);
+ const value step = !isNil(sl) && !isNil(cdr(sl))? cadr(sl) : "";
+
+ // Handle OAuth authorize request step
+ if (step == "authorize") {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(authorize(args, r, sc));
+ }
+
+ // Handle OAuth access_token request step
+ if (step == "access_token") {
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(access_token(args, r, sc));
+ }
+
+ // Redirect to the login page
+ r->ap_auth_type = const_cast<char*>(atype);
+ return httpd::reportStatus(openauth::login(dc.login, r));
+}
+
+/**
+ * Process the module configuration.
+ */
+int postConfigMerge(ServerConf& mainsc, server_rec* s) {
+ if (s == NULL)
+ return OK;
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2);
+ debug(httpd::serverName(s), "modoauth2::postConfigMerge::serverName");
+
+ // Merge configuration from main server
+ if (isNil(sc.appkeys))
+ sc.appkeys = mainsc.appkeys;
+ sc.mc = mainsc.mc;
+ sc.cs = mainsc.cs;
+
+ return postConfigMerge(mainsc, s->next);
+}
+
+int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) {
+ gc_scoped_pool pool(p);
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2);
+ debug(httpd::serverName(s), "modoauth2::postConfig::serverName");
+
+ // Merge server configurations
+ return postConfigMerge(sc, s);
+}
+
+/**
+ * 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_oauth2);
+ if(psc == NULL) {
+ cfailure << "[Tuscany] Due to one or more errors mod_tuscany_oauth2 loading failed. Causing apache to stop loading." << endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+ ServerConf& sc = *psc;
+
+ // Connect to Memcached
+ if (isNil(sc.mcaddrs))
+ sc.mc = *(new (gc_new<memcache::MemCached>()) memcache::MemCached("localhost", 11211));
+ else
+ sc.mc = *(new (gc_new<memcache::MemCached>()) memcache::MemCached(sc.mcaddrs));
+
+ // Setup a CURL session
+ sc.cs = *(new (gc_new<http::CURLSession>()) http::CURLSession(sc.ca, sc.cert, sc.key));
+
+ // Merge the updated configuration into the virtual hosts
+ postConfigMerge(sc, s->next);
+}
+
+/**
+ * Configuration commands.
+ */
+const char* confAppKey(cmd_parms *cmd, unused void *c, const char *arg1, const char* arg2, const char* arg3) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.appkeys = cons<list<value> >(mklist<value>(arg1, mklist<value>(arg2, arg3)), sc.appkeys);
+ return NULL;
+}
+const char* confMemcached(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.mcaddrs = cons<string>(arg, sc.mcaddrs);
+ return NULL;
+}
+const char* confEnabled(cmd_parms *cmd, void *c, const int arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.enabled = (bool)arg;
+ return NULL;
+}
+const char* confLogin(cmd_parms *cmd, void *c, const char* arg) {
+ gc_scoped_pool pool(cmd->pool);
+ DirConf& dc = httpd::dirConf<DirConf>(c);
+ dc.login = arg;
+ return NULL;
+}
+const char* confCAFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.ca = arg;
+ return NULL;
+}
+const char* confCertFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.cert = arg;
+ return NULL;
+}
+const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) {
+ gc_scoped_pool pool(cmd->pool);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
+ sc.key = arg;
+ return NULL;
+}
+
+/**
+ * HTTP server module declaration.
+ */
+const command_rec commands[] = {
+ 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"),
+ AP_INIT_TAKE1("AuthOAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "OAuth 2.0 login page"),
+ AP_INIT_TAKE1("AuthOAuthSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "OAUth 2.0 SSL CA certificate file"),
+ AP_INIT_TAKE1("AuthOAuthSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "OAuth 2.0 SSL certificate file"),
+ AP_INIT_TAKE1("AuthOAuthSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "OAuth 2.0 SSL certificate key file"),
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
+};
+
+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);
+}
+
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_oauth2 = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::oauth2::DirConf>, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::oauth2::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::oauth2::commands, tuscany::oauth2::registerHooks
+};
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-conf b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-conf
new file mode 100755
index 0000000000..dc3a6ebc9d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-conf
@@ -0,0 +1,59 @@
+#!/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=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+conf=`cat $root/conf/httpd.conf | grep "# Generated by: httpd-conf"`
+host=`echo $conf | awk '{ print $6 }'`
+
+# Configure HTTPD mod_tuscany_oauth module
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: oauth-conf $*
+# Load support for OAuth authentication
+LoadModule mod_tuscany_oauth1 $here/libmod_tuscany_oauth1.so
+LoadModule mod_tuscany_oauth2 $here/libmod_tuscany_oauth2.so
+
+EOF
+
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: oauth-conf $*
+# Enable OAuth authentication
+<Location />
+AuthType Open
+AuthName "$host"
+AuthOAuth On
+AuthOAuthLoginPage /login
+Require valid-user
+</Location>
+
+# Configure OAuth App keys
+Include $root/cert/oauth-keys.conf
+Include $HOME/.oauth/*-key.conf
+
+EOF
+
+cat >$root/cert/oauth-keys.conf <<EOF
+# Generated by: oauth-conf $*
+# OAuth App keys
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-memcached-conf b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-memcached-conf
new file mode 100755
index 0000000000..23a82a0486
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth-memcached-conf
@@ -0,0 +1,32 @@
+#!/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=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+host=$2
+port=$3
+
+# Configure HTTPD mod_tuscany_oauth module cache
+cat >>$root/conf/auth.conf <<EOF
+# Generated by: oauth-memcached-conf $*
+AddAuthOAuthMemcached $host:$port
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth.composite b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth.composite
new file mode 100644
index 0000000000..c2025493c8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth.composite
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="oauth">
+
+ <component name="Protected">
+ <t:implementation.widget location="protected/index.html"/>
+ <reference name="userInfo" target="UserInfo"/>
+ </component>
+
+ <component name="UserInfo">
+ <t:implementation.scheme script="user-info.scm"/>
+ <service name="info">
+ <t:binding.jsonrpc uri="info"/>
+ </service>
+ <property name="user">?</property>
+ <property name="email">?</property>
+ <property name="nickname">?</property>
+ <property name="fullname">?</property>
+ <property name="firstname">?</property>
+ <property name="lastname">?</property>
+ <property name="realm">?</property>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth1-appkey-conf b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth1-appkey-conf
new file mode 100755
index 0000000000..fca7d4e8f3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth1-appkey-conf
@@ -0,0 +1,36 @@
+#!/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=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+name=$2
+id=$3
+secret=$4
+
+# Configure an OAuth 1.0 app key
+mkdir -p $root/cert
+umask 0007
+
+cat >>$root/cert/oauth-keys.conf <<EOF
+# Generated by: oauth1-appkey-conf $*
+AddAuthOAuth1AppKey $name $id $secret
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth2-appkey-conf b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth2-appkey-conf
new file mode 100755
index 0000000000..0a7986f07e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/oauth2-appkey-conf
@@ -0,0 +1,36 @@
+#!/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=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+name=$2
+id=$3
+secret=$4
+
+# Configure an OAuth 2.0 app key
+mkdir -p $root/cert
+umask 0007
+
+cat >>$root/cert/oauth-keys.conf <<EOF
+# Generated by: oauth2-appkey-conf $*
+AddAuthOAuth2AppKey $name $id $secret
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/start-mixed-test b/sandbox/sebastien/cpp/apr-2/modules/oauth/start-mixed-test
new file mode 100755
index 0000000000..bfd7667ce4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/start-mixed-test
@@ -0,0 +1,67 @@
+#!/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.
+
+# Test supporting both OpenID and OAuth in the same app
+here=`readlink -f $0`; here=`dirname $here`
+
+# Setup
+../../components/cache/memcached-start 11212
+../../components/cache/memcached-start 11213
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453
+
+./oauth-conf tmp
+./oauth-memcached-conf tmp localhost 11212
+./oauth-memcached-conf tmp localhost 11213
+
+# Configure your app keys here
+./oauth1-appkey-conf tmp twitter.com app2345 secret7890
+./oauth1-appkey-conf tmp linkedin.com app3456 secret4567
+./oauth2-appkey-conf tmp facebook.com app1234 secret6789
+./oauth2-appkey-conf tmp github.com app5678 secret8901
+
+../openid/openid-conf tmp
+../openid/openid-step2-conf tmp
+../openid/openid-memcached-conf tmp localhost 11212
+../openid/openid-memcached-conf tmp localhost 11213
+
+../http/open-auth-conf tmp
+../http/passwd-auth-conf tmp foo foo
+
+# For this test to work you need to add your form, oauth and open id ids
+# to the authorized user group
+../../modules/http/group-auth-conf tmp foo
+../../modules/http/group-auth-conf tmp 123456
+../../modules/http/group-auth-conf tmp https://www.google.com/accounts/o8/id?id=12345678
+
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite oauth.composite
+
+Alias /login/index.html $here/htdocs/login/mixed.html
+
+EOF
+
+../../modules/http/httpd-start tmp
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/start-test b/sandbox/sebastien/cpp/apr-2/modules/oauth/start-test
new file mode 100755
index 0000000000..0e859ce6e6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/start-test
@@ -0,0 +1,54 @@
+#!/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.
+
+# Setup
+../../ubuntu/ip-redirect-all 80 8090
+../../ubuntu/ip-redirect-all 443 8453
+
+../../components/cache/memcached-start 11212
+../../components/cache/memcached-start 11213
+
+../../modules/http/ssl-ca-conf tmp localhost
+../../modules/http/ssl-cert-conf tmp localhost
+../../modules/http/httpd-conf tmp localhost 8090/80 htdocs
+../../modules/http/httpd-ssl-conf tmp 8453/443
+
+./oauth-conf tmp
+./oauth-memcached-conf tmp localhost 11212
+./oauth-memcached-conf tmp localhost 11213
+
+# Configure your app keys here
+./oauth1-appkey-conf tmp twitter.com app2345 secret7890
+./oauth1-appkey-conf tmp linkedin.com app3456 secret4567
+./oauth2-appkey-conf tmp facebook.com app1234 secret6789
+./oauth2-appkey-conf tmp github.com app5678 secret8901
+
+# For this test to work you need to add your oauth user id to the
+# authorized user group
+../../modules/http/group-auth-conf tmp 123456
+
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite oauth.composite
+EOF
+
+../../modules/http/httpd-start tmp
+
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/stop-test b/sandbox/sebastien/cpp/apr-2/modules/oauth/stop-test
new file mode 100755
index 0000000000..a0587f8cb7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/stop-test
@@ -0,0 +1,24 @@
+#!/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.
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+
+../../components/cache/memcached-stop 11212
+../../components/cache/memcached-stop 11213
diff --git a/sandbox/sebastien/cpp/apr-2/modules/oauth/user-info.scm b/sandbox/sebastien/cpp/apr-2/modules/oauth/user-info.scm
new file mode 100644
index 0000000000..4960a0a455
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/oauth/user-info.scm
@@ -0,0 +1,36 @@
+; 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.
+
+; OAuth support test case
+
+(define (get id user email nickname fullname firstname lastname realm) (list "text/html" (list
+ "<html><body><p>The following info is generated on the server:</p><div>User: " (user) "</div><div>Email: " (email) "</div><div>Nickname: " (nickname) "</div><div>Fullname: " (fullname) "</div><div>Firstname: " (firstname) "</div><div>Lastname: " (lastname) "</div><div>Realm: " (realm) "</div></body></html>")))
+
+(define (getuser user email nickname fullname firstname lastname realm) (user))
+
+(define (getemail user email nickname fullname firstname lastname realm) (email))
+
+(define (getnickname user email nickname fullname firstname lastname realm) (nickname))
+
+(define (getfullname user email nickname fullname firstname lastname realm) (fullname))
+
+(define (getfirstname user email nickname fullname firstname lastname realm) (firstname))
+
+(define (getlastname user email nickname fullname firstname lastname realm) (lastname))
+
+(define (getrealm user email nickname fullname firstname lastname realm) (realm))
+