const failable accessToken()

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