From 57ff384203570508e81cdf5dfaa0cb96478e7654 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Mon, 21 Nov 2011 08:47:12 +0000 Subject: Improvements to the auth implementation. Refactor logout page, handle auth redirects in XHR responses and allow auth to work off an OpenID AX attribute or OAuth resource attribute. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1204401 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/modules/edit/Makefile.am | 6 +- sca-cpp/trunk/modules/edit/htdocs/index.html | 23 +++++- sca-cpp/trunk/modules/edit/htdocs/login/index.html | 57 +++------------ .../trunk/modules/edit/htdocs/logout/index.html | 81 --------------------- .../modules/edit/htdocs/public/notauth/index.html | 16 ++++- .../modules/edit/htdocs/public/notfound/index.html | 16 ++++- .../modules/edit/htdocs/public/notyet/index.html | 16 ++++- .../modules/edit/htdocs/public/oops/index.html | 16 ++++- sca-cpp/trunk/modules/http/http.hpp | 7 +- sca-cpp/trunk/modules/http/mod-security-conf | 4 +- sca-cpp/trunk/modules/js/htdocs/component.js | 30 +++++--- sca-cpp/trunk/modules/js/htdocs/ui.js | 15 ++++ sca-cpp/trunk/modules/js/htdocs/util.js | 9 ++- sca-cpp/trunk/modules/oauth/mod-oauth1.cpp | 84 ++++++++++++---------- sca-cpp/trunk/modules/oauth/mod-oauth2.cpp | 69 ++++++++++-------- sca-cpp/trunk/modules/oauth/oauth-conf | 16 ++++- sca-cpp/trunk/modules/openid/openid-conf | 1 + 17 files changed, 246 insertions(+), 220 deletions(-) delete mode 100644 sca-cpp/trunk/modules/edit/htdocs/logout/index.html (limited to 'sca-cpp') diff --git a/sca-cpp/trunk/modules/edit/Makefile.am b/sca-cpp/trunk/modules/edit/Makefile.am index 98c0ecc2e9..6bf47676d1 100644 --- a/sca-cpp/trunk/modules/edit/Makefile.am +++ b/sca-cpp/trunk/modules/edit/Makefile.am @@ -18,7 +18,7 @@ if WANT_PYTHON moddir = $(prefix)/modules/edit -dist_mod_SCRIPTS = start stop ssl-start mkapplinks +dist_mod_SCRIPTS = start stop ssl-start mkapplinks config-backup data-backup BUILT_SOURCES = htdocs/config.js htdocs/public/config.js htdocs/config.js: @@ -27,9 +27,9 @@ htdocs/config.js: htdocs/public/config.js: touch htdocs/public/config.js -not_minified = htdocs/public/iframe.html htdocs/create/index.html htdocs/page/index.html htdocs/login/index.html htdocs/public/notfound/index.html htdocs/public/oops/index.html htdocs/graph/index.html htdocs/public/notauth/index.html htdocs/account/index.html htdocs/home/index.html htdocs/index.html htdocs/public/notyet/index.html htdocs/clone/index.html htdocs/stats/index.html htdocs/app/index.html htdocs/logout/index.html htdocs/store/index.html htdocs/config.js htdocs/public/config.js +not_minified = htdocs/public/iframe.html htdocs/create/index.html htdocs/page/index.html htdocs/login/index.html htdocs/public/notfound/index.html htdocs/public/oops/index.html htdocs/graph/index.html htdocs/public/notauth/index.html htdocs/account/index.html htdocs/home/index.html htdocs/index.html htdocs/public/notyet/index.html htdocs/clone/index.html htdocs/stats/index.html htdocs/app/index.html htdocs/store/index.html htdocs/config.js htdocs/public/config.js -minified = htdocs/public/iframe-min.html htdocs/create/index-min.html htdocs/page/index-min.html htdocs/login/index-min.html htdocs/public/notfound/index-min.html htdocs/public/oops/index-min.html htdocs/graph/index-min.html htdocs/public/notauth/index-min.html htdocs/account/index-min.html htdocs/home/index-min.html htdocs/index-min.html htdocs/public/notyet/index-min.html htdocs/clone/index-min.html htdocs/stats/index-min.html htdocs/app/index-min.html htdocs/logout/index-min.html htdocs/store/index-min.html htdocs/config-min.js htdocs/public/config-min.js +minified = htdocs/public/iframe-min.html htdocs/create/index-min.html htdocs/page/index-min.html htdocs/login/index-min.html htdocs/public/notfound/index-min.html htdocs/public/oops/index-min.html htdocs/graph/index-min.html htdocs/public/notauth/index-min.html htdocs/account/index-min.html htdocs/home/index-min.html htdocs/index-min.html htdocs/public/notyet/index-min.html htdocs/clone/index-min.html htdocs/stats/index-min.html htdocs/app/index-min.html htdocs/store/index-min.html htdocs/config-min.js htdocs/public/config-min.js resources = edit.composite *.py htdocs/*.cmf htdocs/*.ico htdocs/home/*.png htdocs/app/*.cmf htdocs/home/*.b64 htdocs/*.txt htdocs/public/*.png htdocs/public/*.b64 palettes/*/palette.composite accounts/*/*.account apps/*/app.composite apps/*/app.stats apps/*/htdocs/app.html dashboards/*/user.apps store/*/store.apps ${not_minified} ${minified} diff --git a/sca-cpp/trunk/modules/edit/htdocs/index.html b/sca-cpp/trunk/modules/edit/htdocs/index.html index 0a57717a06..3bc1529dbb 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/index.html @@ -260,7 +260,7 @@ function showmenu(mdiv, view, appname) { ui.menu(isNil(config.compose)? 'Composition' : config.compose, '/#view=graph&app=' + appname, '_view', view == 'graph'))), mklist( ui.menu('Account', '/#view=account', '_view', view == 'account'), - ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false))); + ui.signedin()? ui.menufunc('Sign out', 'logout();', false) : ui.menu('Sign in', '/login/', '_self', false))); } /** @@ -422,6 +422,27 @@ window.onnavigate = function(url) { return showview(url); }; +/** + * Handle login redirect. + */ +window.onloginredirect = function(e) { + document.location = '/login/'; +}; + +/** + * Log the current user out. + */ +function logout() { + // Clear session cookie and user-specific local storage entries + var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + document.cookie = reset; + localStorage.removeItem('/r/EditWidget/accounts'); + localStorage.removeItem('/r/EditWidget/dashboards'); + //localStorage.clear(); + document.location = '/login/'; + return true; +} + /** * Handle history. */ diff --git a/sca-cpp/trunk/modules/edit/htdocs/login/index.html b/sca-cpp/trunk/modules/edit/htdocs/login/index.html index 982f8cf446..9052abe8d3 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/login/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/login/index.html @@ -32,19 +32,6 @@

Sign in

- -
@@ -68,57 +55,32 @@ + - - -
- -

Sign out

- -
- - - - - -
- - diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/notauth/index.html b/sca-cpp/trunk/modules/edit/htdocs/public/notauth/index.html index 8a688c9aa5..f366533e17 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/notauth/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/notauth/index.html @@ -110,12 +110,26 @@ var cdiv = $('content'); function showmenu(mdiv) { mdiv.innerHTML = ui.menubar( mklist(ui.menu('Home', '/', '_view', false)), - mklist(ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false))); + mklist(ui.signedin()? ui.menufunc('Sign out', 'logout();', false) : ui.menu('Sign in', '/login/', '_self', false))); } showmenu(mdiv); cdiv.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight); +/** + * Log the current user out. + */ +function logout() { + // Clear session cookie and user-specific local storage entries + var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + document.cookie = reset; + localStorage.removeItem('/r/EditWidget/accounts'); + localStorage.removeItem('/r/EditWidget/dashboards'); + //localStorage.clear(); + document.location = '/login/'; + return true; +} + /** * Handle orientation change. */ diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/notfound/index.html b/sca-cpp/trunk/modules/edit/htdocs/public/notfound/index.html index b7ba34c416..24efb159ea 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/notfound/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/notfound/index.html @@ -111,12 +111,26 @@ var cdiv = $('content'); function showmenu(mdiv) { mdiv.innerHTML = ui.menubar( mklist(ui.menu('Home', '/', '_view', false)), - mklist(ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false))); + mklist(ui.signedin()? ui.menufunc('Sign out', 'logout();', false) : ui.menu('Sign in', '/login/', '_self', false))); } showmenu(mdiv); cdiv.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight); +/** + * Log the current user out. + */ +function logout() { + // Clear session cookie and user-specific local storage entries + var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + document.cookie = reset; + localStorage.removeItem('/r/EditWidget/accounts'); + localStorage.removeItem('/r/EditWidget/dashboards'); + //localStorage.clear(); + document.location = '/login/'; + return true; +} + /** * Handle orientation change. */ diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/notyet/index.html b/sca-cpp/trunk/modules/edit/htdocs/public/notyet/index.html index ca164f3172..b8457485fb 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/notyet/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/notyet/index.html @@ -111,12 +111,26 @@ var cdiv = $('content'); function showmenu(mdiv) { mdiv.innerHTML = ui.menubar( mklist(ui.menu('Home', '/', '_view', false)), - mklist(ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false))); + mklist(ui.signedin()? ui.menufunc('Sign out', 'logout();', false) : ui.menu('Sign in', '/login/', '_self', false))); } showmenu(mdiv); cdiv.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight); +/** + * Log the current user out. + */ +function logout() { + // Clear session cookie and user-specific local storage entries + var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + document.cookie = reset; + localStorage.removeItem('/r/EditWidget/accounts'); + localStorage.removeItem('/r/EditWidget/dashboards'); + //localStorage.clear(); + document.location = '/login/'; + return true; +} + /** * Handle orientation change. */ diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/oops/index.html b/sca-cpp/trunk/modules/edit/htdocs/public/oops/index.html index 8cfe2f6537..ca3e7706e3 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/oops/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/oops/index.html @@ -110,12 +110,26 @@ var cdiv = $('content'); function showmenu(mdiv) { mdiv.innerHTML = ui.menubar( mklist(ui.menu('Home', '/', '_view', false)), - mklist(ui.signedin()? ui.menu('Sign out', '/logout/', '_self', false) : ui.menu('Sign in', '/login/', '_self', false))); + mklist(ui.signedin()? ui.menufunc('Sign out', 'logout();', false) : ui.menu('Sign in', '/login/', '_self', false))); } showmenu(mdiv); cdiv.style.top = ui.pixpos(mdiv.offsetTop + mdiv.offsetHeight); +/** + * Log the current user out. + */ +function logout() { + // Clear session cookie and user-specific local storage entries + var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/'; + document.cookie = reset; + localStorage.removeItem('/r/EditWidget/accounts'); + localStorage.removeItem('/r/EditWidget/dashboards'); + //localStorage.clear(); + document.location = '/login/'; + return true; +} + /** * Handle orientation change. */ diff --git a/sca-cpp/trunk/modules/http/http.hpp b/sca-cpp/trunk/modules/http/http.hpp index 5cf174f4e1..530f3c0c5c 100644 --- a/sca-cpp/trunk/modules/http/http.hpp +++ b/sca-cpp/trunk/modules/http/http.hpp @@ -869,8 +869,11 @@ const failable recv(char* c, const size_t l, const CURLSession& cs) { ostringstream& queryString(const list > args, ostringstream& os) { if (isNil(args)) return os; - debug(car(args), "http::queryString::arg"); - os << car(car(args)) << "=" << c_str(cadr(car(args))); + const list arg = car(args); + debug(arg, "http::queryString::arg"); + if (isNil(arg) || isNil(cdr(arg))) + return queryString(cdr(args), os); + os << car(arg) << "=" << c_str(cadr(arg)); if (!isNil(cdr(args))) os << "&"; return queryString(cdr(args), os); diff --git a/sca-cpp/trunk/modules/http/mod-security-conf b/sca-cpp/trunk/modules/http/mod-security-conf index c9f0728f88..a1373906fd 100755 --- a/sca-cpp/trunk/modules/http/mod-security-conf +++ b/sca-cpp/trunk/modules/http/mod-security-conf @@ -81,8 +81,8 @@ IH %{MULTIPART_FILE_LIMIT_EXCEEDED}'" SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" "phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'" # Avoid a potential RegEx DoS condition -SecPcreMatchLimit 1000 -SecPcreMatchLimitRecursion 1000 +SecPcreMatchLimit 10000 +SecPcreMatchLimitRecursion 10000 SecRule TX:/^MSC_/ "!@streq 0" "phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" # Detect slow DoS attacks diff --git a/sca-cpp/trunk/modules/js/htdocs/component.js b/sca-cpp/trunk/modules/js/htdocs/component.js index d991f9aa61..10b4535470 100644 --- a/sca-cpp/trunk/modules/js/htdocs/component.js +++ b/sca-cpp/trunk/modules/js/htdocs/component.js @@ -265,13 +265,16 @@ HTTPBindingClient.prototype.get = function(id, cb) { if (http.getResponseHeader("X-Login") != null) { // Detect redirect to a login page try { - cb(null, new HTTPBindingClient.Exception(403, 'X-Login')); + var le = new HTTPBindingClient.Exception(403, 'X-Login'); + if (window.onloginredirect) + window.onloginredirect(le); + return cb(null, le); } catch(cbe) {} } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { // Report empty response try { - cb(null, new HTTPBindingClient.Exception(403, 'No-Content')); + return cb(null, new HTTPBindingClient.Exception(403, 'No-Content')); } catch(cbe) {} } else { @@ -282,7 +285,7 @@ HTTPBindingClient.prototype.get = function(id, cb) { localStorage.setItem(u, http.responseText); } try { - cb(http.responseText); + return cb(http.responseText); } catch(cbe) {} } } @@ -291,7 +294,7 @@ HTTPBindingClient.prototype.get = function(id, cb) { // Pass exception if we didn't have a local result if (item == null) { try { - cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + return cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); } catch(cbe) {} } } @@ -309,7 +312,10 @@ HTTPBindingClient.prototype.get = function(id, cb) { if (http.getResponseHeader("X-Login") != null) { // Detect redirect to a login page - throw new HTTPBindingClient.Exception(403, 'X-Login'); + var le = new HTTPBindingClient.Exception(403, 'X-Login'); + if (window.onloginredirect) + window.onloginredirect(le); + throw le; } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { @@ -341,7 +347,10 @@ HTTPBindingClient.prototype.getnocache = function(id, cb) { if (http.getResponseHeader("X-Login") != null) { // Detect redirect to a login page try { - return cb(null, new HTTPBindingClient.Exception(403, 'X-Login')); + var le = new HTTPBindingClient.Exception(403, 'X-Login'); + if (window.onloginredirect) + window.onloginredirect(le); + return cb(null, le); } catch(cbe) {} } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { @@ -352,12 +361,12 @@ HTTPBindingClient.prototype.getnocache = function(id, cb) { } else { try { - cb(http.responseText); + return cb(http.responseText); } catch(cbe) {} } } else { try { - cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + return cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); } catch(cbe) {} } } @@ -374,7 +383,10 @@ HTTPBindingClient.prototype.getnocache = function(id, cb) { if (http.getResponseHeader("X-Login") != null) { // Detect redirect to a login page - throw new HTTPBindingClient.Exception(403, 'X-Login'); + var le = new HTTPBindingClient.Exception(403, 'X-Login'); + if (window.onloginredirect) + window.onloginredirect(le); + throw le; } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { diff --git a/sca-cpp/trunk/modules/js/htdocs/ui.js b/sca-cpp/trunk/modules/js/htdocs/ui.js index ee65d62e56..eabf851b55 100644 --- a/sca-cpp/trunk/modules/js/htdocs/ui.js +++ b/sca-cpp/trunk/modules/js/htdocs/ui.js @@ -274,6 +274,21 @@ ui.menu = function(name, href, target, hilight) { return new Menu(); }; +ui.menufunc = function(name, fun, hilight) { + function Menu() { + this.content = function() { + function href(fun, html) { + return '' + html + ''; + } + + if (hilight) + return href(fun, '' + name + ''); + return href(fun, '' + name + ''); + }; + } + return new Menu(); +}; + ui.menubar = function(left, right) { var bar = '
Sign in with your Google account
' + '
'; diff --git a/sca-cpp/trunk/modules/js/htdocs/util.js b/sca-cpp/trunk/modules/js/htdocs/util.js index 86e17c4f60..60c8a0c8e6 100644 --- a/sca-cpp/trunk/modules/js/htdocs/util.js +++ b/sca-cpp/trunk/modules/js/htdocs/util.js @@ -315,8 +315,15 @@ function properties(o) { * Convert a host name to a domain name. */ function domainname(host) { + var ds = host.indexOf('//'); + if (ds != -1) + return domainname(host.substring(ds + 2)); + var s = host.indexOf('/'); + if (s != -1) + return domainname(host.substring(0, s)); var h = reverse(host.split('.')); - return reverse(mklist(car(h), cadr(h))).join('.'); + var d = (!isNil(cddr(h)) && caddr(h) == 'www')? mklist(car(h), cadr(h), caddr(h)) : mklist(car(h), cadr(h)); + return reverse(d).join('.'); } /** diff --git a/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp b/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp index ca7f562b60..2381b16810 100644 --- a/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp +++ b/sca-cpp/trunk/modules/oauth/mod-oauth1.cpp @@ -81,6 +81,7 @@ public: const char* dir; bool enabled; string login; + list > scopeattrs; }; /** @@ -93,40 +94,36 @@ const failable userInfo(const value& sid, const memcache::MemCached& mc) /** * Handle an authenticated request. */ -const failable authenticated(const list >& info, request_rec* r) { +const failable authenticated(const list >& attrs, const list >& info, request_rec* r) { debug(info, "modoauth1::authenticated::info"); - // Store user info in the request - const list realm = assoc("realm", info); - if (isNil(realm) || isNil(cdr(realm))) - return mkfailure("Couldn't retrieve realm"); - apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm)))); - - const list id = assoc("id", info); - if (isNil(id) || isNil(cdr(id))) - return mkfailure("Couldn't retrieve user id"); - r->user = apr_pstrdup(r->pool, c_str(cadr(id))); - - const list email = assoc("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 screenname = assoc("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 name = assoc("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 firstname = assoc("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 lastname = assoc("last-name", info); - if (!isNil(lastname) && !isNil(cdr(lastname))) - apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "LASTNAME"), apr_pstrdup(r->pool, c_str(cadr(lastname)))); - return OK; + if (isNil(attrs)) { + + // Store user id in an environment variable + const list id = assoc("id", info); + if (isNil(id) || isNil(cdr(id))) + return mkfailure("Couldn't retrieve user id"); + apr_table_set(r->subprocess_env, "OAUTH1_ID", apr_pstrdup(r->pool, c_str(cadr(id)))); + + // If the request user field has not been mapped to another attribute, map the + // OAuth id attribute to it + if (r->user == NULL || r->user[0] == '\0') + r->user = apr_pstrdup(r->pool, c_str(cadr(id))); + return OK; + } + + // Store each configure OAuth scope attribute in an environment variable + const list a = car(attrs); + const list v = assoc(cadr(a), info); + if (!isNil(v) && !isNil(cdr(v))) { + + // Map the REMOTE_USER attribute to the request user field + if (string(car(a)) == "REMOTE_USER") + r->user = apr_pstrdup(r->pool, c_str(cadr(v))); + else + apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, c_str(car(a))), apr_pstrdup(r->pool, c_str(cadr(v)))); + } + return authenticated(cdr(attrs), info, r); } /** @@ -414,7 +411,7 @@ static int checkAuthn(request_rec *r) { const failable info = userInfo(content(sid), sc.mc); if (hasContent(info)) { r->ap_auth_type = const_cast(atype); - return httpd::reportStatus(authenticated(content(info), r)); + return httpd::reportStatus(authenticated(dc.scopeattrs, content(info), r)); } } @@ -461,6 +458,8 @@ int postConfigMerge(ServerConf& mainsc, server_rec* s) { // Merge configuration from main server if (isNil(sc.appkeys)) sc.appkeys = mainsc.appkeys; + if (isNil(sc.mcaddrs)) + sc.mcaddrs = mainsc.mcaddrs; sc.mc = mainsc.mc; sc.cs = mainsc.cs; @@ -564,18 +563,25 @@ const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) { sc.key = arg; return NULL; } +const char* confScopeAttr(cmd_parms *cmd, void* c, const char* arg1, const char* arg2) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf(c); + dc.scopeattrs = cons >(mklist(arg1, arg2), dc.scopeattrs); + 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_TAKE3("AddAuthOAuth1AppKey", (const char*(*)())confAppKey, NULL, RSRC_CONF, "OAuth 1.0 name app-id app-key"), AP_INIT_ITERATE("AddAuthOAuthMemcached", (const char*(*)())confMemcached, NULL, RSRC_CONF, "Memcached server host:port"), - AP_INIT_FLAG("AuthOAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "OAuth 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"), + AP_INIT_FLAG("AuthOAuth", (const char*(*)())confEnabled, NULL, OR_AUTHCFG, "OAuth 1.0 authentication On | Off"), + AP_INIT_TAKE1("AuthOAuthLoginPage", (const char*(*)())confLogin, NULL, OR_AUTHCFG, "OAuth 1.0 login page"), + AP_INIT_TAKE1("AuthOAuthSSLCACertificateFile", (const char*(*)())confCAFile, NULL, RSRC_CONF, "OAUth 1.0 SSL CA certificate file"), + AP_INIT_TAKE1("AuthOAuthSSLCertificateFile", (const char*(*)())confCertFile, NULL, RSRC_CONF, "OAuth 1.0 SSL certificate file"), + AP_INIT_TAKE1("AuthOAuthSSLCertificateKeyFile", (const char*(*)())confCertKeyFile, NULL, RSRC_CONF, "OAuth 1.0 SSL certificate key file"), + AP_INIT_TAKE2("AddAuthOAuth1ScopeAttr", (const char*(*)())confScopeAttr, NULL, OR_AUTHCFG, "OAuth 1.0 scope attribute"), {NULL, NULL, NULL, 0, NO_ARGS, NULL} }; diff --git a/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp b/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp index 41d722f1e2..3d567040ac 100644 --- a/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp +++ b/sca-cpp/trunk/modules/oauth/mod-oauth2.cpp @@ -75,6 +75,7 @@ public: const char* dir; bool enabled; string login; + list > scopeattrs; }; /** @@ -87,39 +88,36 @@ const failable userInfo(const value& sid, const memcache::MemCached& mc) /** * Handle an authenticated request. */ -const failable authenticated(const list >& info, request_rec* r) { +const failable authenticated(const list >& attrs, const list >& info, request_rec* r) { debug(info, "modoauth2::authenticated::info"); - // Store user info in the request - const list realm = assoc("realm", info); - if (isNil(realm) || isNil(cdr(realm))) - return mkfailure("Couldn't retrieve realm"); - apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm)))); - - const list id = assoc("id", info); - if (isNil(id) || isNil(cdr(id))) - return mkfailure("Couldn't retrieve user id"); - r->user = apr_pstrdup(r->pool, c_str(cadr(id))); - - const list email = assoc("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 fullname = assoc("name", info); - if (!isNil(fullname) && !isNil(cdr(fullname))) { - apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "NICKNAME"), apr_pstrdup(r->pool, c_str(cadr(fullname)))); - apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FULLNAME"), apr_pstrdup(r->pool, c_str(cadr(fullname)))); - } + if (isNil(attrs)) { - const list firstname = assoc("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)))); + // Store user id in an environment variable + const list id = assoc("id", info); + if (isNil(id) || isNil(cdr(id))) + return mkfailure("Couldn't retrieve user id"); + apr_table_set(r->subprocess_env, "OAUTH2_ID", apr_pstrdup(r->pool, c_str(cadr(id)))); - const list lastname = assoc("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 the request user field has not been mapped to another attribute, map the + // OAuth id attribute to it + if (r->user == NULL || r->user[0] == '\0') + r->user = apr_pstrdup(r->pool, c_str(cadr(id))); + return OK; + } - return OK; + // Store each configure OAuth scope attribute in an environment variable + const list a = car(attrs); + const list v = assoc(cadr(a), info); + if (!isNil(v) && !isNil(cdr(v))) { + + // Map the REMOTE_USER attribute to the request user field + if (string(car(a)) == "REMOTE_USER") + r->user = apr_pstrdup(r->pool, c_str(cadr(v))); + else + apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, c_str(car(a))), apr_pstrdup(r->pool, c_str(cadr(v)))); + } + return authenticated(cdr(attrs), info, r); } /** @@ -139,6 +137,7 @@ const failable authorize(const list >& args, request_rec* r, co const list info = assoc("mod_oauth2_info", args); if (isNil(info) || isNil(cdr(info))) return mkfailure("Missing mod_oauth2_info parameter"); + const list display = assoc("mod_oauth2_display", args); // Build the redirect URI const list > rargs = mklist >(mklist("mod_oauth2_step", "access_token"), tok, cid, info); @@ -152,7 +151,8 @@ const failable authorize(const list >& args, request_rec* r, co list appkey = cadr(app); // Redirect to the authorize URI - const list > aargs = mklist >(mklist("client_id", car(appkey)), mklist("scope", "email"), mklist("redirect_uri", httpd::escape(redir))); + const list adisplay = (isNil(display) || isNil(cdr(display)))? list() : mklist("display", cadr(display)); + const list > aargs = mklist >(mklist("client_id", car(appkey)), mklist("scope", "email"), adisplay, mklist("redirect_uri", httpd::escape(redir))); const string uri = httpd::unescape(cadr(auth)) + string("?") + http::queryString(aargs); debug(uri, "modoauth2::authorize::uri"); return httpd::externalRedirect(uri, r); @@ -266,7 +266,7 @@ static int checkAuthn(request_rec *r) { const failable info = userInfo(content(sid), sc.mc); if (hasContent(info)) { r->ap_auth_type = const_cast(atype); - return httpd::reportStatus(authenticated(content(info), r)); + return httpd::reportStatus(authenticated(dc.scopeattrs, content(info), r)); } } @@ -313,6 +313,8 @@ int postConfigMerge(ServerConf& mainsc, server_rec* s) { // Merge configuration from main server if (isNil(sc.appkeys)) sc.appkeys = mainsc.appkeys; + if (isNil(sc.mcaddrs)) + sc.mcaddrs = mainsc.mcaddrs; sc.mc = mainsc.mc; sc.cs = mainsc.cs; @@ -416,6 +418,12 @@ const char* confCertKeyFile(cmd_parms *cmd, unused void *c, const char *arg) { sc.key = arg; return NULL; } +const char* confScopeAttr(cmd_parms *cmd, void* c, const char* arg1, const char* arg2) { + gc_scoped_pool pool(cmd->pool); + DirConf& dc = httpd::dirConf(c); + dc.scopeattrs = cons >(mklist(arg1, arg2), dc.scopeattrs); + return NULL; +} /** * HTTP server module declaration. @@ -428,6 +436,7 @@ const command_rec commands[] = { 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"), + AP_INIT_TAKE2("AddAuthOAuth2ScopeAttr", (const char*(*)())confScopeAttr, NULL, OR_AUTHCFG, "OAuth 2.0 scope attribute"), {NULL, NULL, NULL, 0, NO_ARGS, NULL} }; diff --git a/sca-cpp/trunk/modules/oauth/oauth-conf b/sca-cpp/trunk/modules/oauth/oauth-conf index 856eea7f39..21fc51cac8 100755 --- a/sca-cpp/trunk/modules/oauth/oauth-conf +++ b/sca-cpp/trunk/modules/oauth/oauth-conf @@ -53,9 +53,23 @@ cat >>$root/conf/auth.conf < AuthType Open AuthName "$host" +Require valid-user AuthOAuth On AuthOAuthLoginPage /login -Require valid-user +AddAuthOAuth2ScopeAttr REALM realm +AddAuthOAuth2ScopeAttr REMOTE_USER email +AddAuthOAuth2ScopeAttr EMAIL email +AddAuthOAuth2ScopeAttr NICKNAME name +AddAuthOAuth2ScopeAttr FULLNAME name +AddAuthOAuth2ScopeAttr FIRSTNAME first_name +AddAuthOAuth2ScopeAttr LASTNAME last_name +AddAuthOAuth1ScopeAttr REALM realm +AddAuthOAuth1ScopeAttr REMOTE_USER email +AddAuthOAuth1ScopeAttr EMAIL email +AddAuthOAuth1ScopeAttr NICKNAME screen_name +AddAuthOAuth2ScopeAttr FULLNAME name +AddAuthOAuth1ScopeAttr FIRSTNAME first-name +AddAuthOAuth1ScopeAttr LASTNAME last-name # Configure OAuth App keys diff --git a/sca-cpp/trunk/modules/openid/openid-conf b/sca-cpp/trunk/modules/openid/openid-conf index 021c8b1e82..c6e63c128d 100755 --- a/sca-cpp/trunk/modules/openid/openid-conf +++ b/sca-cpp/trunk/modules/openid/openid-conf @@ -45,6 +45,7 @@ AuthOpenIDEnabled On AuthOpenIDCookiePath / AuthOpenIDCookieName TuscanyOpenAuth AuthOpenIDLoginPage /login/ +AuthOpenIDAXAdd REMOTE_USER http://axschema.org/contact/email AuthOpenIDAXAdd EMAIL http://axschema.org/contact/email AuthOpenIDAXAdd FULLNAME http://axschema.org/namePerson AuthOpenIDAXAdd NICKNAME http://axschema.org/namePerson/friendly -- cgit v1.2.3