summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-09-19 00:09:52 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-09-19 00:09:52 +0000
commitddf34aa2e69d6c90b4fe95516168254a80eb32f3 (patch)
tree7e5273c1e222b2cb8d523f2bc4087fe15bc9bcb2 /sca-cpp/trunk/modules
parentb796454ac3a94879f122cc19ddec5a7ff87fe5ee (diff)
Improvements to the oauth module and support for oauth 1.0a using liboauth.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@998571 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/modules')
-rw-r--r--sca-cpp/trunk/modules/http/httpd.hpp2
-rw-r--r--sca-cpp/trunk/modules/json/json.hpp4
-rw-r--r--sca-cpp/trunk/modules/oauth/Makefile.am21
-rw-r--r--sca-cpp/trunk/modules/oauth/htdocs/index.html20
-rw-r--r--sca-cpp/trunk/modules/oauth/htdocs/login/index.html70
-rw-r--r--sca-cpp/trunk/modules/oauth/htdocs/login/mixed.html69
-rw-r--r--sca-cpp/trunk/modules/oauth/mod-oauth1.cpp565
-rw-r--r--sca-cpp/trunk/modules/oauth/mod-oauth2.cpp (renamed from sca-cpp/trunk/modules/oauth/mod-oauth.cpp)207
-rwxr-xr-xsca-cpp/trunk/modules/oauth/oauth-conf15
-rwxr-xr-xsca-cpp/trunk/modules/oauth/oauth-memcached-conf2
-rw-r--r--sca-cpp/trunk/modules/oauth/oauth.composite8
-rw-r--r--sca-cpp/trunk/modules/oauth/oauth.hpp97
-rwxr-xr-xsca-cpp/trunk/modules/oauth/oauth1-appkey-conf (renamed from sca-cpp/trunk/modules/oauth/oauth-app-conf)16
-rwxr-xr-xsca-cpp/trunk/modules/oauth/oauth2-appkey-conf36
-rwxr-xr-xsca-cpp/trunk/modules/oauth/start-mixed-test7
-rwxr-xr-xsca-cpp/trunk/modules/oauth/start-test7
-rw-r--r--sca-cpp/trunk/modules/oauth/user-info.scm16
17 files changed, 973 insertions, 189 deletions
diff --git a/sca-cpp/trunk/modules/http/httpd.hpp b/sca-cpp/trunk/modules/http/httpd.hpp
index 870aed71b7..528404b8fc 100644
--- a/sca-cpp/trunk/modules/http/httpd.hpp
+++ b/sca-cpp/trunk/modules/http/httpd.hpp
@@ -245,6 +245,8 @@ const string unescape(const string& uri) {
const list<value> queryArg(const string& s) {
debug(s, "httpd::queryArg::string");
const list<string> t = tokenize("=", s);
+ if (isNil(cdr(t)))
+ return mklist<value>(c_str(car(t)), "");
return mklist<value>(c_str(car(t)), cadr(t));
}
diff --git a/sca-cpp/trunk/modules/json/json.hpp b/sca-cpp/trunk/modules/json/json.hpp
index bade096b86..fdf752a362 100644
--- a/sca-cpp/trunk/modules/json/json.hpp
+++ b/sca-cpp/trunk/modules/json/json.hpp
@@ -166,6 +166,8 @@ const list<value> jsPropertiesToValues(const list<value>& propertiesSoFar, JSObj
jsval idv;
JS_IdToValue(cx, id, &idv);
if(JSVAL_IS_STRING(idv)) {
+ if (isNil(val) && !isList(val))
+ return jsPropertiesToValues(propertiesSoFar, o, i, cx);
const string name = JS_GetStringBytes(JSVAL_TO_STRING(idv));
if (substr(name, 0, 1) == atsign)
return jsPropertiesToValues(cons<value>(mklist<value>(attribute, c_str(substr(name, 1)), val), propertiesSoFar), o, i, cx);
@@ -194,6 +196,8 @@ const value jsValToValue(const jsval& jsv, const JSONContext& cx) {
}
case JSTYPE_OBJECT: {
JSObject* o = JSVAL_TO_OBJECT(jsv);
+ if (o == NULL)
+ return value();
JSObject* i = JS_NewPropertyIterator(cx, o);
if(i == NULL)
return value(list<value> ());
diff --git a/sca-cpp/trunk/modules/oauth/Makefile.am b/sca-cpp/trunk/modules/oauth/Makefile.am
index 077b50bddf..84bbe32eec 100644
--- a/sca-cpp/trunk/modules/oauth/Makefile.am
+++ b/sca-cpp/trunk/modules/oauth/Makefile.am
@@ -17,18 +17,23 @@
if WANT_OAUTH
-INCLUDES = -I${HTTPD_INCLUDE}
+INCLUDES = -I${HTTPD_INCLUDE} -I${LIBOAUTH_INCLUDE}
-dist_mod_SCRIPTS = oauth-conf oauth-memcached-conf oauth-app-conf
+dist_mod_SCRIPTS = oauth-conf oauth-memcached-conf oauth1-appkey-conf oauth2-appkey-conf
moddir=$(prefix)/modules/oauth
-mod_LTLIBRARIES = libmod_tuscany_oauth.la
-noinst_DATA = libmod_tuscany_oauth.so
+mod_LTLIBRARIES = libmod_tuscany_oauth1.la libmod_tuscany_oauth2.la
+noinst_DATA = libmod_tuscany_oauth1.so libmod_tuscany_oauth2.so
-libmod_tuscany_oauth_la_SOURCES = mod-oauth.cpp
-libmod_tuscany_oauth_la_LDFLAGS = -lxml2 -lcurl -lmozjs
-libmod_tuscany_oauth.so:
- ln -s .libs/libmod_tuscany_oauth.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/unprotected/index.html
diff --git a/sca-cpp/trunk/modules/oauth/htdocs/index.html b/sca-cpp/trunk/modules/oauth/htdocs/index.html
index e6295a93b5..dd75b736db 100644
--- a/sca-cpp/trunk/modules/oauth/htdocs/index.html
+++ b/sca-cpp/trunk/modules/oauth/htdocs/index.html
@@ -25,16 +25,28 @@ var component = new tuscany.sca.Component("Protected");
var userInfo = new tuscany.sca.Reference("userInfo");
var user = userInfo.apply("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");
</script>
</head>
<body>
<h1>Protected area - It works!</h1>
<p>The following info is returned by a JSONRPC service:</p>
-<div id="user"></div>
-<div id="email"></div>
+<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>
<script type="text/javascript">
-document.getElementById('user').innerHTML="User: " + user;
-document.getElementById('email').innerHTML="Email: " + email;
+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;
</script>
<p><a href="info">User info</a></p>
<p><a href="login">Sign in</a></p>
diff --git a/sca-cpp/trunk/modules/oauth/htdocs/login/index.html b/sca-cpp/trunk/modules/oauth/htdocs/login/index.html
index a8ed099fae..607c55ca18 100644
--- a/sca-cpp/trunk/modules/oauth/htdocs/login/index.html
+++ b/sca-cpp/trunk/modules/oauth/htdocs/login/index.html
@@ -17,7 +17,7 @@
under the License.
-->
-<html><body><h1>Sign in with an OAuth 2.0 provider</h1>
+<html><body><h1>Sign in with an OAuth provider</h1>
<script type="text/javascript">
function queryParams() {
@@ -45,38 +45,70 @@ if (typeof(oauthReferrer()) == 'undefined') {
document.location = '/';
}
-function submitSignin(w) {
+function submitSignin2(w) {
parms = w();
- document.signin.mod_oauth_authorize.value = parms[0];
- document.signin.mod_oauth_access_token.value = parms[1];
- document.signin.mod_oauth_client_id.value = parms[2];
- document.signin.mod_oauth_info.value = parms[3];
- document.signin.action = oauthReferrer();
- document.signin.submit();
+ 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', 'app1234', 'https://graph.facebook.com/me'];
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'testfacebookapp', 'https://graph.facebook.com/me'];
return parms;
}
function withGithub() {
- var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'app2345', 'https://github.com/api/v2/json/user/show'];
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'testgithubapp', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitSignin1(w) {
+ parms = w();
+ 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', 'testlinkedinapp', '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', 'testtwitterapp', 'https://api.twitter.com/1/statuses/user_timeline.json'];
return parms;
}
</script>
-<form name="signin" action="/" method="GET">
-<input type="hidden" name="mod_oauth_authorize" value=""/>
-<input type="hidden" name="mod_oauth_access_token" value=""/>
-<input type="hidden" name="mod_oauth_client_id" value=""/>
-<input type="hidden" name="mod_oauth_info" value=""/>
-<input type="hidden" name="mod_oauth_step" value="authorize"/>
+<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="fields">
-<p>Sign in with your Facebook account<br/><input type="button" onclick="submitSignin(withFacebook)" value="Sign in"/></p>
-<p>Sign in with your Github account<br/><input type="button" onclick="submitSignin(withGithub)" value="Sign in"/></p>
+<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/sca-cpp/trunk/modules/oauth/htdocs/login/mixed.html b/sca-cpp/trunk/modules/oauth/htdocs/login/mixed.html
index 16246cc621..c187aa2a84 100644
--- a/sca-cpp/trunk/modules/oauth/htdocs/login/mixed.html
+++ b/sca-cpp/trunk/modules/oauth/htdocs/login/mixed.html
@@ -17,7 +17,7 @@
under the License.
-->
-<html><body><h1>Sign in with an OpenID or OAuth 2.0 provider</h1>
+<html><body><h1>Sign in with an OpenID or OAuth provider</h1>
<script type="text/javascript">
function queryParams() {
@@ -91,23 +91,44 @@ function withXRDSEndpoint() {
return document.fields.endpoint.value;
}
-function submitOAuthSignin(w) {
+function submitOAuth2Signin(w) {
parms = w();
- document.oauthSignin.mod_oauth_authorize.value = parms[0];
- document.oauthSignin.mod_oauth_access_token.value = parms[1];
- document.oauthSignin.mod_oauth_client_id.value = parms[2];
- document.oauthSignin.mod_oauth_info.value = parms[3];
- document.oauthSignin.action = openauthReferrer();
- document.oauthSignin.submit();
+ 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', 'app1234', 'https://graph.facebook.com/me'];
+ var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'testfacebookapp', 'https://graph.facebook.com/me'];
return parms;
}
function withGithub() {
- var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'app2345', 'https://github.com/api/v2/json/user/show'];
+ var parms = ['https://github.com/login/oauth/authorize', 'https://github.com/login/oauth/access_token', 'testgithubapp', 'https://github.com/api/v2/json/user/show'];
+ return parms;
+}
+
+function submitOAuth1Signin(w) {
+ parms = w();
+ 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', 'testlinkedinapp', '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', 'testtwitterapp', 'https://api.twitter.com/1/statuses/user_timeline.json'];
return parms;
}
</script>
@@ -139,20 +160,32 @@ function withGithub() {
<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="submitOAuthSignin(withFacebook)" value="Sign in"/></p>
-<p>Sign in with your Github account<br/><input type="button" onclick="submitOAuthSignin(withGithub)" 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="oauthSignin" action="/" method="GET">
-<input type="hidden" name="mod_oauth_authorize" value=""/>
-<input type="hidden" name="mod_oauth_access_token" value=""/>
-<input type="hidden" name="mod_oauth_client_id" value=""/>
-<input type="hidden" name="mod_oauth_info" value=""/>
-<input type="hidden" name="mod_oauth_step" value="authorize"/>
+<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/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp b/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp
new file mode 100644
index 0000000000..23ef90b0dd
--- /dev/null
+++ b/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp
@@ -0,0 +1,565 @@
+/*
+ * 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 "../../components/cache/memcache.hpp"
+#include "oauth.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;
+};
+
+/**
+ * Check user authentication.
+ */
+static int checkUserID(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::checkUserID::input");
+ return OK;
+}
+
+/**
+ * Handle an authenticated request.
+ */
+const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
+ debug(info, "modoauth1::authenticated::info");
+
+ 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))));
+
+ if(r->ap_auth_type == NULL)
+ r->ap_auth_type = const_cast<char*>("OAuth");
+ return DECLINED;
+}
+
+/**
+ * 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 and linkedin profiles and
+ * needs to be made configurable.
+ */
+const failable<list<value> > profileUserInfo(const string& info) {
+ if (substr(info, 0, 1) == "[") {
+ // JSON profile
+ json::JSONContext 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));
+ if (isNil(uv) || isNil(cdr(uv)))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ const list<value> iv = cdr(uv);
+ return iv;
+
+ } else {
+ // 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);
+ if (isNil(pv) || isNil(cdr(pv)))
+ return mkfailure<list<value> >("Couldn't retrieve user info");
+ const list<value> iv = cdr(pv);
+ return iv;
+ }
+}
+
+/**
+ * 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(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(oauth::cookie(sid)));
+ return httpd::externalRedirect(httpd::url(r->uri, r), r);
+}
+
+/**
+ * Handle a request.
+ */
+int handler(request_rec* r) {
+ // Decline if we're not enabled or if the user is already
+ // authenticated by another module
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth1);
+ if(!dc.enabled)
+ return DECLINED;
+ if (r->user != NULL || apr_table_get(r->subprocess_env, "SSL_REMOTE_USER") != NULL)
+ return DECLINED;
+
+ gc_scoped_pool pool(r->pool);
+ httpdDebugRequest(r, "modoauth1::handler::input");
+ const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth1);
+
+ // Get session id from the request
+ const maybe<string> sid = oauth::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 = oauth::userInfo(content(sid), sc.mc);
+ if (hasContent(info))
+ 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 OpenID authentication
+ if (!isNil(assoc<value>("openid_identifier", args)))
+ return DECLINED;
+
+ // Decline if the request is for OAuth2 authentication
+ 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")
+ return httpd::reportStatus(authorize(args, r, sc));
+
+ // Handle OAuth access_token request step
+ if (step == "access_token")
+ return httpd::reportStatus(access_token(args, r, sc));
+
+ // Redirect to the login page
+ return httpd::reportStatus(oauth::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_user_id(checkUserID, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_handler(handler, NULL, NULL, APR_HOOK_FIRST);
+}
+
+}
+}
+
+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/sca-cpp/trunk/modules/oauth/mod-oauth.cpp b/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp
index e7158c14b0..60eadc282c 100644
--- a/sca-cpp/trunk/modules/oauth/mod-oauth.cpp
+++ b/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp
@@ -34,13 +34,14 @@
#include "../http/httpd.hpp"
#include "../http/http.hpp"
#include "../../components/cache/memcache.hpp"
+#include "oauth.hpp"
extern "C" {
-extern module AP_MODULE_DECLARE_DATA mod_tuscany_oauth;
+extern module AP_MODULE_DECLARE_DATA mod_tuscany_oauth2;
}
namespace tuscany {
-namespace oauth {
+namespace oauth2 {
/**
* Server configuration.
@@ -55,7 +56,7 @@ public:
string ca;
string cert;
string key;
- list<list<value> > apps;
+ list<list<value> > appkeys;
list<string> mcaddrs;
memcache::MemCached mc;
http::CURLSession cs;
@@ -80,7 +81,7 @@ public:
*/
static int checkUserID(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_oauth);
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth2);
if (!dc.enabled)
return DECLINED;
const char* atype = ap_auth_type(r);
@@ -88,44 +89,15 @@ static int checkUserID(request_rec *r) {
return DECLINED;
gc_scoped_pool pool(r->pool);
- httpdDebugRequest(r, "modoauth::checkUserID::input");
+ httpdDebugRequest(r, "modoauth2::checkUserID::input");
return OK;
}
/**
- * Return the session id from a request.
- */
-const maybe<string> sessionID(const list<string> c) {
- if (isNil(c))
- return maybe<string>();
- const list<string> kv = tokenize("=", car(c));
- if (!isNil(kv) && !isNil(cdr(kv))) {
- if (car(kv) == "TuscanyOpenAuth")
- return cadr(kv);
- }
- return sessionID(cdr(c));
-}
-
-const maybe<string> sessionID(const request_rec* r) {
- const char* c = apr_table_get(r->headers_in, "Cookie");
- debug(c, "modoauth::sessionid::cookies");
- if (c == NULL)
- return maybe<string>();
- return sessionID(tokenize(";", c));
-}
-
-/**
- * Return the user info for a session.
- */
-const failable<value> userInfo(const value& sid, const ServerConf& sc) {
- return memcache::get(mklist<value>("tuscanyOpenAuth", sid), sc.mc);
-}
-
-/**
* Handle an authenticated request.
*/
const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
- debug(info, "modoauth::authenticated::info");
+ debug(info, "modoauth2::authenticated::info");
const list<value> id = assoc<value>("id", info);
if (isNil(id) || isNil(cdr(id)))
@@ -156,116 +128,101 @@ const failable<int> authenticated(const list<list<value> >& info, request_rec* r
}
/**
- * Redirect to the configured login page.
- */
-const failable<int> login(const string& page, request_rec* r) {
- const list<list<value> > largs = mklist<list<value> >(mklist<value>("openauth_referrer", httpd::escape(httpd::url(r->uri, r))));
- const string loc = httpd::url(page, r) + string("?") + httpd::queryString(largs);
- debug(loc, "modoauth::login::uri");
- return httpd::externalRedirect(loc, r);
-}
-
-/**
* Handle an authorize request.
*/
-const failable<int> authorize(const list<list<value> >& args, request_rec* r) {
+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_oauth_authorize", args);
+ const list<value> auth = assoc<value>("mod_oauth2_authorize", args);
if (isNil(auth) || isNil(cdr(auth)))
- return mkfailure<int>("Missing mod_oauth_authorize parameter");
- const list<value> tok = assoc<value>("mod_oauth_access_token", args);
+ 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_oauth_access_token parameter");
- const list<value> cid = assoc<value>("mod_oauth_client_id", args);
+ 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_oauth_client_id parameter");
- const list<value> info = assoc<value>("mod_oauth_info", args);
+ 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_oauth_info parameter");
+ return mkfailure<int>("Missing mod_oauth2_info parameter");
// Build the redirect URI
- const list<list<value> > rargs = mklist<list<value> >(mklist<value>("mod_oauth_step", "access_token"), tok, cid, info);
+ 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, "modoauth::authorize::redir");
+ 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", cadr(cid)), mklist<value>("scope", "email"), mklist<value>("redirect_uri", httpd::escape(redir)));
+ 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, "modoauth::authorize::uri");
+ debug(uri, "modoauth2::authorize::uri");
return httpd::externalRedirect(uri, r);
}
/**
- * Convert a session id to a cookie string.
- */
-const string cookie(const string& sid) {
- const time_t t = time(NULL) + 86400;
- char exp[32];
- strftime(exp, 32, "%a, %d-%b-%Y %H:%M:%S GMT", gmtime(&t));
- const string c = string("TuscanyOpenAuth=") + sid + string(";path=/;expires=" + string(exp)) + ";secure=TRUE";
- debug(c, "modoauth::cookie");
- return c;
-}
-
-/**
* 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_oauth_access_token", args);
+ const list<value> tok = assoc<value>("mod_oauth2_access_token", args);
if (isNil(tok) || isNil(cdr(tok)))
- return mkfailure<int>("Missing mod_oauth_access_token parameter");
- const list<value> cid = assoc<value>("mod_oauth_client_id", args);
+ 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_oauth_client_id parameter");
- const list<value> info = assoc<value>("mod_oauth_info", args);
+ 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_oauth_info parameter");
+ 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.apps);
+ 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_oauth_step", "access_token"), tok, cid, info);
+ 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, "modoauth::access_token::redir");
+ debug(redir, "modoauth2::access_token::redir");
// Request access token
- const list<list<value> > targs = mklist<list<value> >(mklist<value>("client_id", cadr(cid)), mklist<value>("redirect_uri", httpd::escape(redir)), mklist<value>("client_secret", cadr(app)), code);
+ 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, "modoauth::access_token::tokenuri");
+ 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, "modoauth::access_token::response");
+ debug(tr, "modoauth2::access_token::response");
const list<value> tv = assoc<value>("access_token", httpd::queryArgs(join("", convertValues<string>(content(tr)))));
- if (isNil(app) || isNil(cdr(app)))
+ if (isNil(tv) || isNil(cdr(tv)))
return mkfailure<int>("Couldn't retrieve access_token");
- debug(tv, "modoauth::access_token::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, "modoauth::access_token::infouri");
+ debug(iuri, "modoauth2::access_token::infouri");
const failable<value> iv = http::get(iuri, sc.cs);
- if (isNil(app) || isNil(cdr(app)))
+ if (!hasContent(iv))
return mkfailure<int>("Couldn't retrieve user info");
- debug(iv, "modoauth::access_token::info");
+ debug(content(iv), "modoauth2::access_token::info");
// Store user info in memcached keyed by session ID
- const value sid = string("OAuth_") + mkrand();
+ 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(cookie(sid)));
+ apr_table_set(r->err_headers_out, "Set-Cookie", c_str(oauth::cookie(sid)));
return httpd::externalRedirect(httpd::url(r->uri, r), r);
}
@@ -275,25 +232,25 @@ const failable<int> access_token(const list<list<value> >& args, request_rec* r,
int handler(request_rec* r) {
// Decline if we're not enabled or if the user is already
// authenticated by another module
- const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth);
+ const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth2);
if(!dc.enabled)
return DECLINED;
if (r->user != NULL || apr_table_get(r->subprocess_env, "SSL_REMOTE_USER") != NULL)
return DECLINED;
gc_scoped_pool pool(r->pool);
- httpdDebugRequest(r, "modoauth::handler::input");
- const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth);
+ httpdDebugRequest(r, "modoauth2::handler::input");
+ const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth2);
// Get session id from the request
- const maybe<string> sid = sessionID(r);
+ const maybe<string> sid = oauth::sessionID(r);
if (hasContent(sid)) {
// Decline if the session id was not created by this module
- if (substr(content(sid), 0, 6) != "OAuth_")
+ 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);
+ const failable<value> info = oauth::userInfo(content(sid), sc.mc);
if (hasContent(info))
return httpd::reportStatus(authenticated(content(info), r));
}
@@ -305,21 +262,25 @@ int handler(request_rec* r) {
if (!isNil(assoc<value>("openid_identifier", args)))
return DECLINED;
+ // Decline if the request is for OAuth1 authentication
+ 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_oauth_step", args);
+ 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")
- return httpd::reportStatus(authorize(args, r));
+ return httpd::reportStatus(authorize(args, r, sc));
// Handle OAuth access_token request step
if (step == "access_token")
return httpd::reportStatus(access_token(args, r, sc));
// Redirect to the login page
- return httpd::reportStatus(login(dc.login, r));
+ return httpd::reportStatus(oauth::login(dc.login, r));
}
/**
@@ -328,12 +289,12 @@ int handler(request_rec* r) {
int postConfigMerge(ServerConf& mainsc, server_rec* s) {
if (s == NULL)
return OK;
- ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth);
- debug(httpd::serverName(s), "modoauth::postConfigMerge::serverName");
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2);
+ debug(httpd::serverName(s), "modoauth2::postConfigMerge::serverName");
// Merge configuration from main server
- if (isNil(sc.apps))
- sc.apps = mainsc.apps;
+ if (isNil(sc.appkeys))
+ sc.appkeys = mainsc.appkeys;
sc.mc = mainsc.mc;
sc.cs = mainsc.cs;
@@ -342,8 +303,8 @@ int postConfigMerge(ServerConf& mainsc, server_rec* s) {
int postConfig(apr_pool_t* p, unused apr_pool_t* plog, unused apr_pool_t* ptemp, server_rec* s) {
gc_scoped_pool pool(p);
- ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth);
- debug(httpd::serverName(s), "modoauth::postConfig::serverName");
+ ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2);
+ debug(httpd::serverName(s), "modoauth2::postConfig::serverName");
// Merge server configurations
return postConfigMerge(sc, s);
@@ -354,9 +315,9 @@ 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_oauth);
+ 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_oauth loading failed. Causing apache to stop loading." << endl;
+ 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;
@@ -377,15 +338,15 @@ void childInit(apr_pool_t* p, server_rec* s) {
/**
* Configuration commands.
*/
-const char* confApp(cmd_parms *cmd, unused void *c, const char *arg1, const char* arg2) {
+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_oauth);
- sc.apps = cons<list<value> >(mklist<value>(arg1, arg2), sc.apps);
+ 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_oauth);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
sc.mcaddrs = cons<string>(arg, sc.mcaddrs);
return NULL;
}
@@ -403,19 +364,19 @@ const char* confLogin(cmd_parms *cmd, void *c, const char* arg) {
}
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_oauth);
+ 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_oauth);
+ 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_oauth);
+ ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
sc.key = arg;
return NULL;
}
@@ -424,13 +385,13 @@ const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) {
* HTTP server module declaration.
*/
const command_rec commands[] = {
- AP_INIT_ITERATE2("AddAuthOAuthApp", (const char*(*)())confApp, NULL, RSRC_CONF, "OAuth app-id app-secret"),
+ 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 authentication On | Off"),
- AP_INIT_TAKE1("AuthOAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "OAuth login page"),
- AP_INIT_TAKE1("AuthOAuthSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "OAUth SSL CA certificate file"),
- AP_INIT_TAKE1("AuthOAuthSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "OAuth SSL certificate file"),
- AP_INIT_TAKE1("AuthOAuthSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "OAuth SSL certificate key file"),
+ 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}
};
@@ -446,14 +407,14 @@ void registerHooks(unused apr_pool_t *p) {
extern "C" {
-module AP_MODULE_DECLARE_DATA mod_tuscany_oauth = {
+module AP_MODULE_DECLARE_DATA mod_tuscany_oauth2 = {
STANDARD20_MODULE_STUFF,
// dir config and merger
- tuscany::httpd::makeDirConf<tuscany::oauth::DirConf>, NULL,
+ tuscany::httpd::makeDirConf<tuscany::oauth2::DirConf>, NULL,
// server config and merger
- tuscany::httpd::makeServerConf<tuscany::oauth::ServerConf>, NULL,
+ tuscany::httpd::makeServerConf<tuscany::oauth2::ServerConf>, NULL,
// commands and hooks
- tuscany::oauth::commands, tuscany::oauth::registerHooks
+ tuscany::oauth2::commands, tuscany::oauth2::registerHooks
};
}
diff --git a/sca-cpp/trunk/modules/oauth/oauth-conf b/sca-cpp/trunk/modules/oauth/oauth-conf
index 7123d8710e..5c3fde2ccc 100755
--- a/sca-cpp/trunk/modules/oauth/oauth-conf
+++ b/sca-cpp/trunk/modules/oauth/oauth-conf
@@ -29,7 +29,8 @@ host=`echo $conf | awk '{ print $6 }'`
cat >>$root/conf/httpd.conf <<EOF
# Generated by: oauth-conf $*
# Load support for OAuth authentication
-LoadModule mod_tuscany_oauth $here/libmod_tuscany_oauth.so
+LoadModule mod_tuscany_oauth1 $here/libmod_tuscany_oauth1.so
+LoadModule mod_tuscany_oauth2 $here/libmod_tuscany_oauth2.so
# Enable OAuth authentication
<Location />
@@ -49,10 +50,20 @@ AuthOAuth Off
AuthOAuth Off
</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
cat >>$root/conf/vhost-ssl.conf <<EOF
-# Generated by: openid-conf $*
+# Generated by: oauth-conf $*
# Require OAuth authentication
<Location />
AuthType Open
diff --git a/sca-cpp/trunk/modules/oauth/oauth-memcached-conf b/sca-cpp/trunk/modules/oauth/oauth-memcached-conf
index 8c133688d7..6634511d61 100755
--- a/sca-cpp/trunk/modules/oauth/oauth-memcached-conf
+++ b/sca-cpp/trunk/modules/oauth/oauth-memcached-conf
@@ -25,7 +25,7 @@ port=$3
# Configure HTTPD mod_tuscany_oauth module cache
cat >>$root/conf/httpd.conf <<EOF
-# Generated by: oauth-cache-conf $*
+# Generated by: oauth-memcached-conf $*
AddAuthOAuthMemcached $host:$port
EOF
diff --git a/sca-cpp/trunk/modules/oauth/oauth.composite b/sca-cpp/trunk/modules/oauth/oauth.composite
index b1fc095ce5..0119db22c9 100644
--- a/sca-cpp/trunk/modules/oauth/oauth.composite
+++ b/sca-cpp/trunk/modules/oauth/oauth.composite
@@ -32,8 +32,12 @@
<service name="info">
<t:binding.jsonrpc uri="info"/>
</service>
- <property name="user">anonymous</property>
- <property name="email">anonymous@example.com</property>
+ <property name="user">?</property>
+ <property name="email">?</property>
+ <property name="nickname">?</property>
+ <property name="fullname">?</property>
+ <property name="firstname">?</property>
+ <property name="lastname">?</property>
</component>
</composite>
diff --git a/sca-cpp/trunk/modules/oauth/oauth.hpp b/sca-cpp/trunk/modules/oauth/oauth.hpp
new file mode 100644
index 0000000000..ab92cbd381
--- /dev/null
+++ b/sca-cpp/trunk/modules/oauth/oauth.hpp
@@ -0,0 +1,97 @@
+/*
+ * 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$ */
+
+#ifndef tuscany_oauth_hpp
+#define tuscany_oauth_hpp
+
+/**
+ * OAuth support utility functions.
+ */
+
+#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 "../../components/cache/memcache.hpp"
+
+namespace tuscany {
+namespace oauth {
+
+/**
+ * Return the session id from a request.
+ */
+const maybe<string> sessionID(const list<string> c) {
+ if (isNil(c))
+ return maybe<string>();
+ const list<string> kv = tokenize("=", car(c));
+ if (!isNil(kv) && !isNil(cdr(kv))) {
+ if (car(kv) == "TuscanyOpenAuth")
+ return cadr(kv);
+ }
+ return sessionID(cdr(c));
+}
+
+const maybe<string> sessionID(const request_rec* r) {
+ const char* c = apr_table_get(r->headers_in, "Cookie");
+ debug(c, "oauth::sessionid::cookies");
+ if (c == NULL)
+ return maybe<string>();
+ return sessionID(tokenize(";", c));
+}
+
+/**
+ * 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);
+}
+
+/**
+ * Convert a session id to a cookie string.
+ */
+const string cookie(const string& sid) {
+ const time_t t = time(NULL) + 86400;
+ char exp[32];
+ strftime(exp, 32, "%a, %d-%b-%Y %H:%M:%S GMT", gmtime(&t));
+ const string c = string("TuscanyOpenAuth=") + sid + string(";path=/;expires=" + string(exp)) + ";secure=TRUE";
+ debug(c, "oauth::cookie");
+ return c;
+}
+
+/**
+ * Redirect to the configured login page.
+ */
+const failable<int> login(const string& page, request_rec* r) {
+ const list<list<value> > largs = mklist<list<value> >(mklist<value>("openauth_referrer", httpd::escape(httpd::url(r->uri, r))));
+ const string loc = httpd::url(page, r) + string("?") + httpd::queryString(largs);
+ debug(loc, "oauth::login::uri");
+ return httpd::externalRedirect(loc, r);
+}
+
+}
+}
+
+#endif /* tuscany_oauth_hpp */
diff --git a/sca-cpp/trunk/modules/oauth/oauth-app-conf b/sca-cpp/trunk/modules/oauth/oauth1-appkey-conf
index 56beb0af95..fca7d4e8f3 100755
--- a/sca-cpp/trunk/modules/oauth/oauth-app-conf
+++ b/sca-cpp/trunk/modules/oauth/oauth1-appkey-conf
@@ -20,13 +20,17 @@
here=`readlink -f $0`; here=`dirname $here`
mkdir -p $1
root=`readlink -f $1`
-id=$2
-secret=$3
+name=$2
+id=$3
+secret=$4
-# Configure an OAuth App
-cat >>$root/conf/httpd.conf <<EOF
-# Generated by: oauth-app-conf $*
-AddAuthOAuthApp $id $secret
+# 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/sca-cpp/trunk/modules/oauth/oauth2-appkey-conf b/sca-cpp/trunk/modules/oauth/oauth2-appkey-conf
new file mode 100755
index 0000000000..0a7986f07e
--- /dev/null
+++ b/sca-cpp/trunk/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/sca-cpp/trunk/modules/oauth/start-mixed-test b/sca-cpp/trunk/modules/oauth/start-mixed-test
index 7a96773dd3..468e6861d8 100755
--- a/sca-cpp/trunk/modules/oauth/start-mixed-test
+++ b/sca-cpp/trunk/modules/oauth/start-mixed-test
@@ -32,7 +32,12 @@ here=`readlink -f $0`; here=`dirname $here`
./oauth-conf tmp
./oauth-memcached-conf tmp localhost 11212
./oauth-memcached-conf tmp localhost 11213
-./oauth-app-conf tmp app1234 secret6789
+
+# Configure your app keys here
+./oauth1-appkey-conf tmp testtwitterapp app2345 secret7890
+./oauth1-appkey-conf tmp testlinkedinapp app3456 secret4567
+./oauth2-appkey-conf tmp testfacebookapp app1234 secret6789
+./oauth2-appkey-conf tmp testgithubapp app5678 secret8901
../openid/openid-conf tmp
../openid/openid-step2-conf tmp
diff --git a/sca-cpp/trunk/modules/oauth/start-test b/sca-cpp/trunk/modules/oauth/start-test
index 0946397f1a..47171a91ae 100755
--- a/sca-cpp/trunk/modules/oauth/start-test
+++ b/sca-cpp/trunk/modules/oauth/start-test
@@ -29,7 +29,12 @@
./oauth-conf tmp
./oauth-memcached-conf tmp localhost 11212
./oauth-memcached-conf tmp localhost 11213
-./oauth-app-conf tmp app1234 secret6789
+
+# Configure your app keys here
+./oauth1-appkey-conf tmp testtwitterapp app2345 secret7890
+./oauth1-appkey-conf tmp testlinkedinapp app3456 secret4567
+./oauth2-appkey-conf tmp testfacebookapp app1234 secret6789
+./oauth2-appkey-conf tmp testgithubapp app5678 secret8901
../../modules/server/server-conf tmp
../../modules/server/scheme-conf tmp
diff --git a/sca-cpp/trunk/modules/oauth/user-info.scm b/sca-cpp/trunk/modules/oauth/user-info.scm
index 0c4ebcfaf7..58a84f86b0 100644
--- a/sca-cpp/trunk/modules/oauth/user-info.scm
+++ b/sca-cpp/trunk/modules/oauth/user-info.scm
@@ -17,10 +17,18 @@
; OAuth support test case
-(define (get id user email) (list "text/html" (list
- "<html><body><p>The following info is generated on the server:</p><div>User: " (user) "</div><div>Email: " (email) "</div></body></html>")))
+(define (get id user email nickname fullname firstname lastname) (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></body></html>")))
-(define (getuser user email) (user))
+(define (getuser user email nickname fullname firstname lastname) (user))
-(define (getemail user email) (email))
+(define (getemail user email nickname fullname firstname lastname) (email))
+
+(define (getnickname user email nickname fullname firstname lastname) (nickname))
+
+(define (getfullname user email nickname fullname firstname lastname) (fullname))
+
+(define (getfirstname user email nickname fullname firstname lastname) (firstname))
+
+(define (getlastname user email nickname fullname firstname lastname) (lastname))