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
This commit is contained in:
jsdelfino 2010-09-19 00:09:52 +00:00
parent b796454ac3
commit ddf34aa2e6
21 changed files with 1018 additions and 202 deletions

View file

@ -96,13 +96,16 @@ Google AppEngine 1.3.2 (http://code.google.com/appengine/)
Java:
a Java 5+ JDK (http://openjdk.java.net/, http://harmony.apache.org/)
OpenID user sign in:
OpenID authentication:
Mod_auth_openid (http://trac.butterfat.net/public/mod_auth_openid)
build it from source at http://github.com/jsdelfino/mod_auth_openid
requires Libopkele (http://kin.klever.net/libopkele/ or
http://github.com/jsdelfino/libopkele)
and HTML Tidy (http://tidy.sourceforge.net/)
OAuth authorization:
Liboauth 0.9.1 (http://liboauth.sourceforge.net/)
XMPP Chat:
Apache Vysper 0.5 (http://mina.apache.org/)
@ -157,7 +160,7 @@ To build the SQL Database utility component (requires PostgreSQL):
To build the Web service utility component (requires Apache Axis2/C):
--enable-webservice
To build the support for OAuth authentication:
To build the support for OAuth authorization:
--enable-oauth
To build the support for OpenID authentication:
@ -197,7 +200,7 @@ dependencies installed under $HOME:
--enable-log --with-thrift=$HOME/thrift-0.2.0-bin \
--with-scribe=$HOME/scribe-2.2-bin \
--enable-openid --with-mod-auth-openid=$HOME/mod-auth-openid-bin \
--enable-oauth \
--enable-oauth --with-liboauth=$HOME/liboauth-0.9.1-bin \
--enable-maintainer-mode

View file

@ -6,8 +6,8 @@ in C++ and integrated with the Apache HTTPD server.
It supports SCA components written in C++ and Python. Experimental support
for other programming languages is under construction. SCA bindings are
available for the JSON-RPC, ATOMPub and RSS protocols. User authentication
is supported using OpenID and OAuth.
available for the JSON-RPC, ATOMPub and RSS protocols. User signin is
implemented using OpenID and OAuth.
Several useful SCA components are provided on top of the SCA runtime, which
can be used to help assemble distributed SCA composite applications:
@ -59,8 +59,8 @@ Here's a rough guide to the Tuscany SCA source tree:
| | |-- http HTTP protocol
| | |-- java Support for Java components
| | |-- json JSON-RPC encoding
| | |-- oauth OAuth authentication
| | |-- openid OpenID authentication
| | |-- oauth User signin using OAuth
| | |-- openid User signin using OpenID
| | |-- python Support for Python components
| | |-- scheme Support for Scheme components
| | |-- server Apache HTTPD server integration

View file

@ -528,6 +528,23 @@ AC_ARG_ENABLE(oauth, [AS_HELP_STRING([--enable-oauth], [enable OAuth support [de
esac ],
[ AC_MSG_RESULT(no)])
if test "${want_oauth}" = "true"; then
# Configure path to Liboauth includes and lib.
AC_MSG_CHECKING([for liboauth])
AC_ARG_WITH([liboauth], [AC_HELP_STRING([--with-liboauth=PATH], [path to liboauth [default=/usr/local]])], [
LIBOAUTH_INCLUDE="${withval}/include"
LIBOAUTH_LIB="${withval}/lib"
AC_MSG_RESULT("${withval}")
], [
LIBOAUTH_INCLUDE="/usr/local/include"
LIBOAUTH_LIB="/usr/local/lib"
AC_MSG_RESULT(/usr/local)
])
AC_SUBST(LIBOAUTH_INCLUDE)
AC_SUBST(LIBOAUTH_LIB)
LIBS="-L${LIBOAUTH_LIB} ${defaultlibs}"
AC_CHECK_LIB([oauth], [oauth_sign_url2], [], [AC_MSG_ERROR([couldn't find a suitable liboauth, use --with-liboauth=PATH])], [-lssl])
AM_CONDITIONAL([WANT_OAUTH], true)
AC_DEFINE([WANT_OAUTH], 1, [enable OAuth support])
@ -739,14 +756,14 @@ if test "${want_chat}" = "true"; then
# Configure path to Libstrophe includes and lib.
AC_MSG_CHECKING([for libstrophe])
AC_ARG_WITH([libstrophe], [AC_HELP_STRING([--with-libstrophe=PATH], [path to libstrophe [default=${HOME}/libstrophe-bin]])], [
AC_ARG_WITH([libstrophe], [AC_HELP_STRING([--with-libstrophe=PATH], [path to libstrophe [default=/usr/local]])], [
LIBSTROPHE_INCLUDE="${withval}/include"
LIBSTROPHE_LIB="${withval}/lib"
AC_MSG_RESULT("${withval}")
], [
LIBSTROPHE_INCLUDE="${HOME}/libstrophe-bin/include"
LIBSTROPHE_LIB="${HOME}/libstrophe-bin/lib"
AC_MSG_RESULT(${HOME}/libstrophe-bin)
LIBSTROPHE_INCLUDE="/usr/local/include"
LIBSTROPHE_LIB="/usr/local/lib"
AC_MSG_RESULT(/usr/local)
])
AC_SUBST(LIBSTROPHE_INCLUDE)
AC_SUBST(LIBSTROPHE_LIB)

View file

@ -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));
}

View file

@ -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> ());

View file

@ -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

View file

@ -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>

View file

@ -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="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="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>

View file

@ -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>

View file

@ -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
};
}

View file

@ -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)))
@ -155,117 +127,102 @@ const failable<int> authenticated(const list<list<value> >& info, request_rec* r
return DECLINED;
}
/**
* 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
};
}

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -246,6 +246,18 @@ if [ "$?" != "0" ]; then
fi
cd $build
# Build Liboauth
wget http://liboauth.sourceforge.net/pool/liboauth-0.9.1.tar.gz
tar xzf liboauth-0.9.1.tar.gz
cd liboauth-0.9.1
./configure --prefix=$build/liboauth-0.9.1-bin CURL_CFLAGS="-I$build/curl-7.19.5-bin/include" CURL_LIBS="-L$build/curl-7.19.5-bin/lib -R$build/curl-7.19.5-bin/lib -lcurl"
make
make install
if [ "$?" != "0" ]; then
exit $?
fi
cd $build
# Build PostgreSQL
sudo apt-get -y install libreadline-dev
if [ "$?" != "0" ]; then
@ -324,7 +336,7 @@ git clone git://git.apache.org/tuscany-sca-cpp.git
cd tuscany-sca-cpp
cp etc/git-exclude .git/info/exclude
./bootstrap
./configure --prefix=$build/tuscany-sca-cpp-bin --with-curl=$build/curl-7.19.5-bin --with-apr=$build/httpd-2.2.16-bin --with-httpd=$build/httpd-2.2.16-bin --with-memcached=$build/memcached-1.4.4-bin --with-tinycdb=$build/tinycdb-0.77-bin --with-js-include=$build/tracemonkey-bin/include/js --with-js-lib=$build/tracemonkey-bin/lib --with-libcloud=$build/libcloud-0.3.1-bin --enable-threads --enable-python --enable-gae --with-gae=$build/google_appengine --enable-java --with-java=/usr/lib/jvm/java-6-openjdk --enable-webservice --with-libxml2=$build/libxml2-2.7.7-bin --with-axis2c=$build/axis2c-1.6.0-bin --enable-queue --with-qpidc=$build/qpidc-0.6-bin --enable-chat --with-libstrophe=$build/libstrophe-bin --with-vysper=$build/vysper-0.5 --enable-sqldb --with-pgsql=$build/postgresql-9.0-bin --enable-log --with-thrift=$build/thrift-0.2.0-bin --with-scribe=$build/scribe-2.2-bin --enable-openid --with-mod-auth-openid=$build/mod-auth-openid-bin --enable-oauth
./configure --prefix=$build/tuscany-sca-cpp-bin --with-curl=$build/curl-7.19.5-bin --with-apr=$build/httpd-2.2.16-bin --with-httpd=$build/httpd-2.2.16-bin --with-memcached=$build/memcached-1.4.4-bin --with-tinycdb=$build/tinycdb-0.77-bin --with-js-include=$build/tracemonkey-bin/include/js --with-js-lib=$build/tracemonkey-bin/lib --with-libcloud=$build/libcloud-0.3.1-bin --enable-threads --enable-python --enable-gae --with-gae=$build/google_appengine --enable-java --with-java=/usr/lib/jvm/java-6-openjdk --enable-webservice --with-libxml2=$build/libxml2-2.7.7-bin --with-axis2c=$build/axis2c-1.6.0-bin --enable-queue --with-qpidc=$build/qpidc-0.6-bin --enable-chat --with-libstrophe=$build/libstrophe-bin --with-vysper=$build/vysper-0.5 --enable-sqldb --with-pgsql=$build/postgresql-9.0-bin --enable-log --with-thrift=$build/thrift-0.2.0-bin --with-scribe=$build/scribe-2.2-bin --enable-openid --with-mod-auth-openid=$build/mod-auth-openid-bin --enable-oauth --with-liboauth=$build/liboauth-0.9.1-bin
make
make install
if [ "$?" != "0" ]; then
@ -333,5 +345,5 @@ fi
cd $build
# Create bin archive
tar czf tuscany-sca-cpp-all-1.0.tar.gz tuscany-sca-cpp tuscany-sca-cpp-bin axis2c-1.6.0-bin libxml2-2.7.7-bin curl-7.19.5-bin httpd-2.2.16-bin tracemonkey-bin google_appengine libstrophe-bin memcached-1.4.4-bin tinycdb-0.77-bin qpidc-0.6-bin vysper-0.5 postgresql-9.0-bin thrift-0.2.0-bin scribe-2.2-bin libcloud-0.3.1-bin htmltidy-bin libopkele-bin mod-auth-openid-bin
tar czf tuscany-sca-cpp-all-1.0.tar.gz tuscany-sca-cpp tuscany-sca-cpp-bin axis2c-1.6.0-bin libxml2-2.7.7-bin curl-7.19.5-bin httpd-2.2.16-bin tracemonkey-bin google_appengine libstrophe-bin memcached-1.4.4-bin tinycdb-0.77-bin qpidc-0.6-bin vysper-0.5 postgresql-9.0-bin thrift-0.2.0-bin scribe-2.2-bin libcloud-0.3.1-bin htmltidy-bin libopkele-bin mod-auth-openid-bin liboauth-0.9.1-bin