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
This commit is contained in:
parent
5a4e8af02b
commit
57ff384203
17 changed files with 240 additions and 214 deletions
sca-cpp/trunk/modules
|
@ -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}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -32,19 +32,6 @@
|
|||
|
||||
<h1>Sign in</h1>
|
||||
|
||||
<!--
|
||||
<form name="passwordSignin" onsubmit="submitPasswordSignin();" method="POST" action="/login/dologin/">
|
||||
<table border="0">
|
||||
<tr><td><b>Username:</b></td></tr>
|
||||
<tr><td><input type="text" id="httpd_username" name="httpd_username" value="" size="15" autocapitalize="off" placeholder="Enter your user name" style="width: 300px;"/></td></tr>
|
||||
<tr><td><b>Password:</b></td></tr>
|
||||
<tr><td><input type="password" name="httpd_password" value="" size="15" placeholder="Enter your password" style="width: 300px;"/></td></tr>
|
||||
<tr><td><input type="submit" value="Sign in" class="graybutton" style="font-weight: bold;"/></td><td></td></tr>
|
||||
</table>
|
||||
<input type="hidden" name="httpd_location" value="/"/>
|
||||
</form>
|
||||
-->
|
||||
|
||||
<form name="openIDForm">
|
||||
<table border="0">
|
||||
<tr><td><b>Sign in with your Google account</b></td></tr>
|
||||
|
@ -68,57 +55,32 @@
|
|||
<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_display" value=""/>
|
||||
<input type="hidden" name="mod_oauth2_step" value="authorize"/>
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">
|
||||
function queryParams() {
|
||||
qp = new Array();
|
||||
qs = window.location.search.substring(1).split('&');
|
||||
for (i = 0; i < qs.length; i++) {
|
||||
e = qs[i].indexOf('=');
|
||||
var qp = new Array();
|
||||
var qs = window.location.search.substring(1).split('&');
|
||||
for (var i = 0; i < qs.length; i++) {
|
||||
var e = qs[i].indexOf('=');
|
||||
if (e > 0)
|
||||
qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1));
|
||||
}
|
||||
return qp;
|
||||
}
|
||||
|
||||
function formReferrer() {
|
||||
r = queryParams()['openauth_referrer'];
|
||||
if (typeof(r) == 'undefined')
|
||||
return '/';
|
||||
s = r.indexOf('//');
|
||||
if (s > 0)
|
||||
r = r.substring(s + 2);
|
||||
s = r.indexOf('/');
|
||||
if (s > 0)
|
||||
r = r.substring(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
function openauthReferrer() {
|
||||
r = queryParams()['openauth_referrer'];
|
||||
if (typeof(r) == 'undefined')
|
||||
var r = queryParams()['openauth_referrer'];
|
||||
if (typeof(r) == 'undefined' || domainname(r) != domainname(window.location.hostname))
|
||||
return '/';
|
||||
q = r.indexOf('?');
|
||||
var q = r.indexOf('?');
|
||||
if (q > 0)
|
||||
return r.substring(0, q);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signin with a userid and password.
|
||||
*/
|
||||
function submitPasswordSignin() {
|
||||
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.passwordSignin.httpd_location.value = formReferrer();
|
||||
document.passwordSignin.submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Signin with OpenID.
|
||||
*/
|
||||
|
@ -151,12 +113,13 @@ function submitOAuth2Signin(w) {
|
|||
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.mod_oauth2_display.value = parms[4];
|
||||
document.oauth2Signin.action = openauthReferrer();
|
||||
document.oauth2Signin.submit();
|
||||
}
|
||||
|
||||
function withFacebook() {
|
||||
var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'facebook.com', 'https://graph.facebook.com/me'];
|
||||
var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'facebook.com', 'https://graph.facebook.com/me', ui.isMobile()? 'touch' : 'page'];
|
||||
return parms;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Sign out</title>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
|
||||
<base href="/logout/"/>
|
||||
<link rel="stylesheet" type="text/css" href="/ui-min.css"/>
|
||||
<script type="text/javascript" src="/all-min.js"></script>
|
||||
</head>
|
||||
<body class="delayed" onload="onload();">
|
||||
<div id="bodydiv" class="bodydiv">
|
||||
|
||||
<h1>Sign out</h1>
|
||||
|
||||
<form name="signout" onsubmit="submitSignout();" action="/login/" method="GET">
|
||||
<input type="submit" id="signOut" value="Sign out" class="graybutton" style="font-weight: bold"/>
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">
|
||||
function submitSignout() {
|
||||
// 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.signout.submit();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle orientation change.
|
||||
*/
|
||||
document.body.onorientationchange = function(e) {
|
||||
//log('onorientationchange');
|
||||
|
||||
// Scroll to the top and hide the address bar
|
||||
window.scrollTo(0, 0);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Document load post processing.
|
||||
*/
|
||||
function onload() {
|
||||
//log('onload');
|
||||
|
||||
// Show the page
|
||||
document.body.style.visibility = 'visible';
|
||||
|
||||
// Scroll to the top and hide the address bar
|
||||
window.scrollTo(0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -869,8 +869,11 @@ const failable<size_t> recv(char* c, const size_t l, const CURLSession& cs) {
|
|||
ostringstream& queryString(const list<list<value> > 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<value> 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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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 '<a href="javascript:void(0)" onclick="' + fun + '">' + html + '</a>';
|
||||
}
|
||||
|
||||
if (hilight)
|
||||
return href(fun, '<span class="tbarsmenu">' + name + '</span>');
|
||||
return href(fun, '<span class="tbaramenu">' + name + '</span>');
|
||||
};
|
||||
}
|
||||
return new Menu();
|
||||
};
|
||||
|
||||
ui.menubar = function(left, right) {
|
||||
var bar = '<table cellpadding="0" cellspacing="0" width="100%" class="tbar"><tr>' +
|
||||
'<td class="dtbar"><table border="0" cellspacing="0" cellpadding="0"><tr>';
|
||||
|
|
|
@ -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('.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,6 +81,7 @@ public:
|
|||
const char* dir;
|
||||
bool enabled;
|
||||
string login;
|
||||
list<list<value> > scopeattrs;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -93,40 +94,36 @@ const failable<value> userInfo(const value& sid, const memcache::MemCached& mc)
|
|||
/**
|
||||
* Handle an authenticated request.
|
||||
*/
|
||||
const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
|
||||
const failable<int> authenticated(const list<list<value> >& attrs, const list<list<value> >& info, request_rec* r) {
|
||||
debug(info, "modoauth1::authenticated::info");
|
||||
|
||||
// Store user info in the request
|
||||
const list<value> realm = assoc<value>("realm", info);
|
||||
if (isNil(realm) || isNil(cdr(realm)))
|
||||
return mkfailure<int>("Couldn't retrieve realm");
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm))));
|
||||
if (isNil(attrs)) {
|
||||
|
||||
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)));
|
||||
// Store user id in an environment variable
|
||||
const list<value> id = assoc<value>("id", info);
|
||||
if (isNil(id) || isNil(cdr(id)))
|
||||
return mkfailure<int>("Couldn't retrieve user id");
|
||||
apr_table_set(r->subprocess_env, "OAUTH1_ID", 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))));
|
||||
// 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;
|
||||
}
|
||||
|
||||
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))));
|
||||
// Store each configure OAuth scope attribute in an environment variable
|
||||
const list<value> a = car(attrs);
|
||||
const list<value> v = assoc<value>(cadr(a), info);
|
||||
if (!isNil(v) && !isNil(cdr(v))) {
|
||||
|
||||
const list<value> name = assoc<value>("name", info);
|
||||
if (!isNil(name) && !isNil(cdr(name)))
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FULLNAME"), apr_pstrdup(r->pool, c_str(cadr(name))));
|
||||
|
||||
const list<value> firstname = assoc<value>("first-name", info);
|
||||
if (!isNil(firstname) && !isNil(cdr(firstname)))
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FIRSTNAME"), apr_pstrdup(r->pool, c_str(cadr(firstname))));
|
||||
|
||||
const list<value> lastname = assoc<value>("last-name", info);
|
||||
if (!isNil(lastname) && !isNil(cdr(lastname)))
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "LASTNAME"), apr_pstrdup(r->pool, c_str(cadr(lastname))));
|
||||
return OK;
|
||||
// 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<value> info = userInfo(content(sid), sc.mc);
|
||||
if (hasContent(info)) {
|
||||
r->ap_auth_type = const_cast<char*>(atype);
|
||||
return httpd::reportStatus(authenticated(content(info), r));
|
||||
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<DirConf>(c);
|
||||
dc.scopeattrs = cons<list<value> >(mklist<value>(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}
|
||||
};
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ public:
|
|||
const char* dir;
|
||||
bool enabled;
|
||||
string login;
|
||||
list<list<value> > scopeattrs;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -87,39 +88,36 @@ const failable<value> userInfo(const value& sid, const memcache::MemCached& mc)
|
|||
/**
|
||||
* Handle an authenticated request.
|
||||
*/
|
||||
const failable<int> authenticated(const list<list<value> >& info, request_rec* r) {
|
||||
const failable<int> authenticated(const list<list<value> >& attrs, const list<list<value> >& info, request_rec* r) {
|
||||
debug(info, "modoauth2::authenticated::info");
|
||||
|
||||
// Store user info in the request
|
||||
const list<value> realm = assoc<value>("realm", info);
|
||||
if (isNil(realm) || isNil(cdr(realm)))
|
||||
return mkfailure<int>("Couldn't retrieve realm");
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "REALM"), apr_pstrdup(r->pool, c_str(cadr(realm))));
|
||||
if (isNil(attrs)) {
|
||||
|
||||
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)));
|
||||
// Store user id in an environment variable
|
||||
const list<value> id = assoc<value>("id", info);
|
||||
if (isNil(id) || isNil(cdr(id)))
|
||||
return mkfailure<int>("Couldn't retrieve user id");
|
||||
apr_table_set(r->subprocess_env, "OAUTH2_ID", apr_pstrdup(r->pool, c_str(cadr(id))));
|
||||
|
||||
const list<value> email = assoc<value>("email", info);
|
||||
if (!isNil(email) && !isNil(cdr(email)))
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "EMAIL"), apr_pstrdup(r->pool, c_str(cadr(email))));
|
||||
|
||||
const list<value> fullname = assoc<value>("name", info);
|
||||
if (!isNil(fullname) && !isNil(cdr(fullname))) {
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "NICKNAME"), apr_pstrdup(r->pool, c_str(cadr(fullname))));
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "FULLNAME"), apr_pstrdup(r->pool, c_str(cadr(fullname))));
|
||||
// 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;
|
||||
}
|
||||
|
||||
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))));
|
||||
// Store each configure OAuth scope attribute in an environment variable
|
||||
const list<value> a = car(attrs);
|
||||
const list<value> v = assoc<value>(cadr(a), info);
|
||||
if (!isNil(v) && !isNil(cdr(v))) {
|
||||
|
||||
const list<value> lastname = assoc<value>("last_name", info);
|
||||
if (!isNil(lastname) && !isNil(cdr(lastname)))
|
||||
apr_table_set(r->subprocess_env, apr_pstrdup(r->pool, "LASTNAME"), apr_pstrdup(r->pool, c_str(cadr(lastname))));
|
||||
|
||||
return OK;
|
||||
// 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<int> authorize(const list<list<value> >& args, request_rec* r, co
|
|||
const list<value> info = assoc<value>("mod_oauth2_info", args);
|
||||
if (isNil(info) || isNil(cdr(info)))
|
||||
return mkfailure<int>("Missing mod_oauth2_info parameter");
|
||||
const list<value> display = assoc<value>("mod_oauth2_display", args);
|
||||
|
||||
// Build the redirect URI
|
||||
const list<list<value> > rargs = mklist<list<value> >(mklist<value>("mod_oauth2_step", "access_token"), tok, cid, info);
|
||||
|
@ -152,7 +151,8 @@ const failable<int> authorize(const list<list<value> >& args, request_rec* r, co
|
|||
list<value> appkey = cadr(app);
|
||||
|
||||
// Redirect to the authorize URI
|
||||
const list<list<value> > aargs = mklist<list<value> >(mklist<value>("client_id", car(appkey)), mklist<value>("scope", "email"), mklist<value>("redirect_uri", httpd::escape(redir)));
|
||||
const list<value> adisplay = (isNil(display) || isNil(cdr(display)))? list<value>() : mklist<value>("display", cadr(display));
|
||||
const list<list<value> > aargs = mklist<list<value> >(mklist<value>("client_id", car(appkey)), mklist<value>("scope", "email"), adisplay, mklist<value>("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<value> info = userInfo(content(sid), sc.mc);
|
||||
if (hasContent(info)) {
|
||||
r->ap_auth_type = const_cast<char*>(atype);
|
||||
return httpd::reportStatus(authenticated(content(info), r));
|
||||
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<DirConf>(c);
|
||||
dc.scopeattrs = cons<list<value> >(mklist<value>(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}
|
||||
};
|
||||
|
||||
|
|
|
@ -53,9 +53,23 @@ cat >>$root/conf/auth.conf <<EOF
|
|||
<Location />
|
||||
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
|
||||
</Location>
|
||||
|
||||
# Configure OAuth App keys
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue