in modules/oauth/mod-oauth2.cpp [238:322]
const failable<int> accessToken(const list<value>& args, request_rec* r, const list<value>& appkeys, const http::CURLSession& cs, const list<value>& scopeattrs, const list<AuthnProviderConf>& apcs, const memcache::MemCached& mc) {
// Extract access_token URI, client ID and authorization code parameters
const list<value> state = assoc<value>("state", args);
if (isNull(state) || isNull(cdr(state)))
return mkfailure<int>("Missing state parameter");
const list<value>& stargs = httpd::queryArgs(httpd::unescape(cadr(state)));
const list<value> ref = assoc<value>("openauth_referrer", stargs);
if (isNull(ref) || isNull(cdr(ref)))
return mkfailure<int>("Missing openauth_referrer parameter");
const list<value> tok = assoc<value>("oauth2_access_token", stargs);
if (isNull(tok) || isNull(cdr(tok)))
return mkfailure<int>("Missing oauth2_access_token parameter");
const list<value> cid = assoc<value>("oauth2_client_id", stargs);
if (isNull(cid) || isNull(cdr(cid)))
return mkfailure<int>("Missing oauth2_client_id parameter");
const list<value> info = assoc<value>("oauth2_info", stargs);
if (isNull(info) || isNull(cdr(info)))
return mkfailure<int>("Missing oauth2_info parameter");
const list<value> code = assoc<value>("code", args);
if (isNull(code) || isNull(cdr(code)))
return mkfailure<int>("Missing code parameter");
// Lookup client app configuration
const list<value> app = assoc<value>(cadr(cid), appkeys);
if (isNull(app) || isNull(cdr(app)))
return mkfailure<int>(string("client id not found: ") + (string)cadr(cid));
list<value> appkey = cadr(app);
// Build the redirect URI
const string redir = httpd::url("/oauth2/access_token/", r);
debug(redir, "modoauth2::access_token::redir");
// Request access token
const list<value> targs = mklist<value>(mklist<value>("client_id", car(appkey)), mklist<value>("redirect_uri", httpd::escape(redir)), mklist<value>("client_secret", cadr(appkey)), code, mklist<value>("grant_type", "authorization_code"));
const string tqs = http::queryString(targs);
debug(tqs, "modoauth2::access_token::tokenqs");
const string turi = httpd::unescape(cadr(tok));
debug(turi, "modoauth2::access_token::tokenuri");
const value tval = mklist<value>(string("application/x-www-form-urlencoded;charset=UTF-8"), mklist<value>(tqs));
const failable<value> ftr = http::post(tval, turi, cs);
if (!hasContent(ftr))
return mkfailure<int>(ftr);
const value tr = content(ftr);
debug(tr, "modoauth2::access_token::response");
if (!isList(tr) || isNull(tr))
return mkfailure<int>("Empty access token");
const list<value> tv = isString(car<value>(tr)) ?
assoc<value>("access_token", httpd::queryArgs(join("", convertValues<string>(cadr<value>(tr))))) :
assoc<value>("access_token", tr);
if (isNull(tv) || isNull(cdr(tv)))
return mkfailure<int>("Couldn't retrieve access_token");
debug(tv, "modoauth2::access_token::token");
// Request user info
// TODO Make this step configurable
const list<value> iargs = mklist<value>(tv);
const string iuri = httpd::unescape(cadr(info)) + string("?") + http::queryString(iargs);
debug(iuri, "modoauth2::access_token::infouri");
const failable<value> profres = http::get(iuri, cs);
if (!hasContent(profres))
return mkfailure<int>("Couldn't retrieve user info");
debug(content(profres), "modoauth2::access_token::info");
// Retrieve the user info from the profile
const failable<list<value> > userinfo = profileUserInfo(cadr(cid), content(profres));
if (!hasContent(userinfo))
return mkfailure<int>(userinfo);
// Validate the authenticated user
const failable<int> authrc = authenticated(content(userinfo), r, scopeattrs, apcs);
if (!hasContent(authrc))
return authrc;
// Store user info in memcached keyed by a session ID
const value sid = string("OAuth2_") + (string)mkrand();
const failable<bool> prc = memcache::put(mklist<value>("tuscanyOAuth2", sid), content(userinfo), mc);
if (!hasContent(prc))
return mkfailure<int>(prc);
// Send the session ID to the client in a cookie
debug(c_str(openauth::cookie("TuscanyOAuth2", sid, httpd::hostName(r))), "modoauth2::access_token::setcookie");
apr_table_set(r->err_headers_out, "Set-Cookie", c_str(openauth::cookie("TuscanyOAuth2", sid, httpd::hostName(r))));
return httpd::externalRedirect(httpd::url(httpd::unescape(cadr(ref)), r), r);
}