/*
 * 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 2.0 authentication.
 */

#include <sys/stat.h>

#define WANT_HTTPD_LOG 1
#include "string.hpp"
#include "stream.hpp"
#include "list.hpp"
#include "tree.hpp"
#include "value.hpp"
#include "monad.hpp"
#include "parallel.hpp"
#include "../http/httpd.hpp"
#include "../http/http.hpp"
#include "../http/openauth.hpp"
#include "../../components/cache/memcache.hpp"

extern "C" {
extern module AP_MODULE_DECLARE_DATA mod_tuscany_oauth2;
}

namespace tuscany {
namespace oauth2 {

/**
 * Server configuration.
 */
class ServerConf {
public:
    ServerConf(apr_pool_t* const p, server_rec* const s) : p(p), server(s) {
    }

    const gc_pool p;
    server_rec* const server;
    gc_mutable_ref<string> ca;
    gc_mutable_ref<string> cert;
    gc_mutable_ref<string> key;
    gc_mutable_ref<list<value> > appkeys;
    gc_mutable_ref<list<string> > mcaddrs;
    gc_mutable_ref<memcache::MemCached> mc;
    gc_mutable_ref<perthread_ptr<http::CURLSession> > cs;
};

/**
 * Authentication provider configuration.
 */
class AuthnProviderConf {
public:
    AuthnProviderConf() : name(), provider(NULL) {
    }
    AuthnProviderConf(const string name, const authn_provider* provider) : name(name), provider(provider) {
    }

    const string name;
    const authn_provider* provider;
};

/**
 * Directory configuration.
 */
class DirConf {
public:
    DirConf(apr_pool_t* const p, const char* const d) : p(p), dir(d), enabled(false), login(emptyString) {
    }

    const gc_pool p;
    const char* const dir;
    bool enabled;
    gc_mutable_ref<string> login;
    gc_mutable_ref<list<value> > scopeattrs;
    gc_mutable_ref<list<AuthnProviderConf> > apcs;
};

/**
 * Run the authnz hooks to authenticate a request.
 */
const failable<int> checkAuthnzProviders(const string& user, request_rec* const r, const list<AuthnProviderConf>& apcs) {
    if (isNil(apcs))
        return mkfailure<int>("Authentication failure for: " + user, HTTP_UNAUTHORIZED);
    const AuthnProviderConf apc = car<AuthnProviderConf>(apcs);
    if (apc.provider == NULL || !apc.provider->check_password)
        return checkAuthnzProviders(user, r, cdr(apcs));

    apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, c_str(apc.name));
    const authn_status auth_result = apc.provider->check_password(r, c_str(string("/oauth2/") + user), "password");
    apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
    if (auth_result != AUTH_GRANTED)
        return checkAuthnzProviders(user, r, cdr(apcs));
    return OK;
}

const failable<int> checkAuthnz(const string& user, request_rec* const r, const list<AuthnProviderConf>& apcs) {
    if (substr(user, 0, 1) == "/")
        return mkfailure<int>(string("Encountered FakeBasicAuth spoof: ") + user, HTTP_UNAUTHORIZED);

    if (isNil(apcs)) {
        const authn_provider* provider = (const authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, AUTHN_DEFAULT_PROVIDER, AUTHN_PROVIDER_VERSION);
        return checkAuthnzProviders(user, r, mklist<AuthnProviderConf>(AuthnProviderConf(AUTHN_DEFAULT_PROVIDER, provider)));
    }
    return checkAuthnzProviders(user, r, apcs);
}

/**
 * Return the user info for a session.
 */
const failable<value> userInfo(const value& sid, const memcache::MemCached& mc) {
    return memcache::get(mklist<value>("tuscanyOAuth2", sid), mc);
}

/**
 * Handle an authenticated request.
 */
const failable<int> authenticated(const list<value>& userinfo, const bool check, request_rec* const r, const list<value>& scopeattrs, const list<AuthnProviderConf>& apcs) {
    debug(userinfo, "modoauth2::authenticated::userinfo");

    if (isNil(scopeattrs)) {

        // Store user id in an environment variable
        const list<value> id = assoc<value>("id", userinfo);
        if (isNil(id) || isNil(cdr(id)))
            return mkfailure<int>("Couldn't retrieve user id", HTTP_UNAUTHORIZED);
        apr_table_set(r->subprocess_env, "OAUTH2_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)));

        // Run the authnz hooks to check the authenticated user
        if (check)
            return checkAuthnz(r->user == NULL? emptyString : r->user, r, apcs);
        return OK;
    }

    // Store each configured OAuth scope attribute in an environment variable
    const list<value> a = car(scopeattrs);
    const list<value> v = assoc<value>(cadr(a), userinfo);
    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(userinfo, check, r, cdr(scopeattrs), apcs);
}

/**
 * Handle an authorize request.
 */
const failable<int> authorize(const list<value>& args, request_rec* const r, const list<value>& appkeys) {
    // Extract authorize, access_token, client ID and info URIs
    const list<value> ref = assoc<value>("openauth_referrer", args);
    if (isNil(ref) || isNil(cdr(ref)))
        return mkfailure<int>("Missing openauth_referrer parameter");
    const list<value> auth = assoc<value>("oauth2_authorize", args);
    if (isNil(auth) || isNil(cdr(auth)))
        return mkfailure<int>("Missing oauth2_authorize parameter");
    const list<value> tok = assoc<value>("oauth2_access_token", args);
    if (isNil(tok) || isNil(cdr(tok)))
        return mkfailure<int>("Missing oauth2_access_token parameter");
    const list<value> cid = assoc<value>("oauth2_client_id", args);
    if (isNil(cid) || isNil(cdr(cid)))
        return mkfailure<int>("Missing oauth2_client_id parameter");
    const list<value> info = assoc<value>("oauth2_info", args);
    if (isNil(info) || isNil(cdr(info)))
        return mkfailure<int>("Missing oauth2_info parameter");
    const list<value> scope = assoc<value>("oauth2_scope", args);
    if (isNil(scope) || isNil(cdr(scope)))
        return mkfailure<int>("Missing oauth2_scope parameter");
    const list<value> display = assoc<value>("oauth2_display", args);

    // Build the redirect URI
    const string redir = httpd::url("/oauth2/access_token/", r);
    debug(redir, "modoauth2::authorize::redir");

    // Build the state URI
    const list<value> stargs = mklist<value>(tok, cid, info, ref);
    const string state = http::queryString(stargs);
    debug(state, "modoauth2::authorize::state");

    // Lookup client app configuration
    const list<value> app = assoc<value>(cadr(cid), appkeys);
    if (isNil(app) || isNil(cdr(app)))
        return mkfailure<int>(string("client id not found: ") + (string)cadr(cid));
    list<value> appkey = cadr(app);

    // Redirect to the authorize URI
    const list<value> adisplay = (isNil(display) || isNil(cdr(display)))? nilListValue : mklist<value>("display", cadr(display));
    const list<value> aargs = mklist<value>(mklist<value>("response_type", "code"), mklist<value>("client_id", car(appkey)), mklist<value>("scope", cadr(scope)), adisplay, mklist<value>("redirect_uri", httpd::escape(redir)), mklist<value>("state", httpd::escape(state)));
    const string uri = httpd::unescape(cadr(auth)) + string("?") + http::queryString(aargs);
    debug(uri, "modoauth2::authorize::uri");
    return httpd::externalRedirect(uri, r);
}

/**
 * Extract user info from a profile/info response.
 * TODO This currently only works for Facebook and Gowalla.
 * User profile parsing needs to be made configurable.
 */
const failable<list<value> > profileUserInfo(const value& cid, const list<value>& info) {
    return cons<value>(mklist<value>("realm", cid), info);
}

/**
 * Handle an access_token request.
 */
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 (isNil(state) || isNil(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 (isNil(ref) || isNil(cdr(ref)))
        return mkfailure<int>("Missing openauth_referrer parameter");
    const list<value> tok = assoc<value>("oauth2_access_token", stargs);
    if (isNil(tok) || isNil(cdr(tok)))
        return mkfailure<int>("Missing oauth2_access_token parameter");
    const list<value> cid = assoc<value>("oauth2_client_id", stargs);
    if (isNil(cid) || isNil(cdr(cid)))
        return mkfailure<int>("Missing oauth2_client_id parameter");
    const list<value> info = assoc<value>("oauth2_info", stargs);
    if (isNil(info) || isNil(cdr(info)))
        return mkfailure<int>("Missing 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), appkeys);
    if (isNil(app) || isNil(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) || isNil(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 (isNil(tv) || isNil(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), true, 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);
}

/**
 * Check user authentication.
 */
static int checkAuthn(request_rec *r) {
    const gc_scoped_pool sp(r->pool);

    // Decline if we're not enabled or AuthType is not set to Open
    const DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_oauth2);
    if (!dc.enabled)
        return DECLINED;
    const char* atype = ap_auth_type(r);
    if (atype == NULL || strcasecmp(atype, "Open"))
        return DECLINED;
    debug_httpdRequest(r, "modoauth2::checkAuthn::input");
    debug(atype, "modoauth2::checkAuthn::auth_type");

    // Get the server configuration
    const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_oauth2);

    // Get session id from the request
    const maybe<string> sid = openauth::sessionID(r, "TuscanyOAuth2");
    if (hasContent(sid)) {
        // Decline if the session id was not created by this module
        if (substr(content(sid), 0, 7) != "OAuth2_")
            return DECLINED;

        // Extract the user info from the auth session
        const failable<value> userinfo = userInfo(content(sid), sc.mc);
        if (!hasContent(userinfo))
            return openauth::reportStatus(mkfailure<int>(reason(userinfo), HTTP_UNAUTHORIZED), dc.login, nilValue, r);
        r->ap_auth_type = const_cast<char*>(atype);
        return openauth::reportStatus(authenticated(content(userinfo), false, r, dc.scopeattrs, dc.apcs), dc.login, nilValue, r);
    }

    // Get the request args
    const list<value> args = httpd::queryArgs(r);

    // Handle OAuth authorize request step
    if (string(r->uri) == "/oauth2/authorize/") {
        r->ap_auth_type = const_cast<char*>(atype);
        return openauth::reportStatus(authorize(args, r, sc.appkeys), dc.login, 1, r);
    }

    // Handle OAuth access_token request step
    if (string(r->uri) == "/oauth2/access_token/") {
        r->ap_auth_type = const_cast<char*>(atype);
        const failable<int> authrc = accessToken(args, r, sc.appkeys, *(*(perthread_ptr<http::CURLSession>*)sc.cs), dc.scopeattrs, dc.apcs, sc.mc);
        return openauth::reportStatus(authrc, dc.login, 1, r);
    }

    // Redirect to the login page, unless we have a session id or an authorization
    // header from another module
    if (apr_table_get(r->headers_in, (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authorization" : "Authorization") != NULL)
        return DECLINED;
    if (hasContent(openauth::sessionID(r, "TuscanyOpenIDAuth")) ||
        hasContent(openauth::sessionID(r, "TuscanyOpenAuth")) ||
        hasContent(openauth::sessionID(r, "TuscanyOAuth1")))
        return DECLINED;
    if ((substr(string(r->uri), 0, 8) == "/oauth1/") || !isNil(assoc<value>("openid_identifier", args)))
        return DECLINED;

    r->ap_auth_type = const_cast<char*>(atype);
    return httpd::reportStatus(openauth::login(dc.login, nilValue, nilValue, r));
}

/**
 * Process the module configuration.
 */
int postConfigMerge(const ServerConf& mainsc, server_rec* const s) {
    if (s == NULL)
        return OK;
    ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2);
    debug(httpd::serverName(s), "modoauth2::postConfigMerge::serverName");

    // Merge configuration from main server
    if (isNil((list<value>)sc.appkeys))
        sc.appkeys = mainsc.appkeys;
    if (isNil((list<string>)sc.mcaddrs))
        sc.mcaddrs = mainsc.mcaddrs;
    sc.mc = mainsc.mc;
    sc.cs = mainsc.cs;

    return postConfigMerge(mainsc, s->next);
}

int postConfig(apr_pool_t* const p, unused apr_pool_t* const plog, unused apr_pool_t* const ptemp, server_rec* const s) {
    const gc_scoped_pool sp(p);

    const ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_oauth2);
    debug(httpd::serverName(s), "modoauth2::postConfig::serverName");

    // Merge server configurations
    return postConfigMerge(sc, s);
}

/**
 * Child process initialization.
 */
void childInit(apr_pool_t* const p, server_rec* const s) {
    const gc_scoped_pool sp(p);

    ServerConf* const 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_oauth2 loading failed. Causing apache to stop loading." << endl;
        exit(APEXIT_CHILDFATAL);
    }
    ServerConf& sc = *psc;

    // Connect to Memcached
    if (isNil((list<string>)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
    const string ca = sc.ca;
    const string cert = sc.cert;
    const string key = sc.key;
    const gc_pool cp = gc_current_pool();
    const lambda<const gc_ptr<http::CURLSession>()> newsession = [ca, cert, key, cp]() -> const gc_ptr<http::CURLSession> {
        const gc_scoped_pool sp(pool(cp));
        return new (gc_new<http::CURLSession>()) http::CURLSession(ca, cert, key, emptyString, 0);
    };
    sc.cs = *(new (gc_new<perthread_ptr<http::CURLSession> >()) perthread_ptr<http::CURLSession>(newsession));

    // Merge the updated configuration into the virtual hosts
    postConfigMerge(sc, s->next);
}

/**
 * Configuration commands.
 */
char* confAppKey(cmd_parms *cmd, unused void *c, char *arg1, char* arg2, char* arg3) {
    const gc_scoped_pool sp(cmd->pool);
    ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
    sc.appkeys = cons<value>(mklist<value>(arg1, mklist<value>(arg2, arg3)), (list<value>)sc.appkeys);
    return NULL;
}
char* confMemcached(cmd_parms *cmd, unused void *c, char *arg) {
    const gc_scoped_pool sp(cmd->pool);
    ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
    sc.mcaddrs = cons<string>(arg, (list<string>)sc.mcaddrs);
    return NULL;
}
char* confEnabled(cmd_parms *cmd, void *c, int arg) {
    const gc_scoped_pool sp(cmd->pool);
    DirConf& dc = httpd::dirConf<DirConf>(c);
    dc.enabled = (bool)arg;
    return NULL;
}
char* confLogin(cmd_parms *cmd, void *c, char* arg) {
    const gc_scoped_pool sp(cmd->pool);
    DirConf& dc = httpd::dirConf<DirConf>(c);
    dc.login = arg;
    return NULL;
}
char* confCAFile(cmd_parms *cmd, unused void *c, char *arg) {
    const gc_scoped_pool sp(cmd->pool);
    ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
    sc.ca = arg;
    return NULL;
}
char* confCertFile(cmd_parms *cmd, unused void *c, char *arg) {
    const gc_scoped_pool sp(cmd->pool);
    ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
    sc.cert = arg;
    return NULL;
}
char* confCertKeyFile(cmd_parms *cmd, unused void *c, char *arg) {
    const gc_scoped_pool sp(cmd->pool);
    ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_oauth2);
    sc.key = arg;
    return NULL;
}
char* confScopeAttr(cmd_parms *cmd, void* c, char* arg1, char* arg2) {
    const gc_scoped_pool sp(cmd->pool);
    DirConf& dc = httpd::dirConf<DirConf>(c);
    dc.scopeattrs = cons<value>(mklist<value>(arg1, arg2), (list<value>)dc.scopeattrs);
    return NULL;
}
char* confAuthnProvider(cmd_parms *cmd, void *c, char* arg) {
    const gc_scoped_pool sp(cmd->pool);
    DirConf& dc = httpd::dirConf<DirConf>(c);

    // Lookup and cache the Authn provider
    const authn_provider* provider = (authn_provider*)ap_lookup_provider(AUTHN_PROVIDER_GROUP, arg, AUTHN_PROVIDER_VERSION);
    if (provider == NULL)
        return apr_psprintf(cmd->pool, "Unknown Authn provider: %s", arg);
    if (!provider->check_password)
        return apr_psprintf(cmd->pool, "The '%s' Authn provider doesn't support password authentication", arg);
    dc.apcs = append<AuthnProviderConf>(dc.apcs, mklist<AuthnProviderConf>(AuthnProviderConf(arg, provider)));
    return NULL;
}

/**
 * HTTP server module declaration.
 */
const command_rec commands[] = {
    AP_INIT_ITERATE("AuthOAuthProvider", (const char*(*)())confAuthnProvider, NULL, OR_AUTHCFG, "Auth providers for a directory or location"),
    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 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_TAKE2("AddAuthOAuth2ScopeAttr", (const char*(*)())confScopeAttr, NULL, OR_AUTHCFG, "OAuth 2.0 scope attribute"),
    {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_authn(checkAuthn, NULL, NULL, APR_HOOK_MIDDLE, AP_AUTH_INTERNAL_PER_CONF);
}

}
}

extern "C" {

module AP_MODULE_DECLARE_DATA mod_tuscany_oauth2 = {
    STANDARD20_MODULE_STUFF,
    // dir config and merger
    tuscany::httpd::makeDirConf<tuscany::oauth2::DirConf>, NULL,
    // server config and merger
    tuscany::httpd::makeServerConf<tuscany::oauth2::ServerConf>, NULL,
    // commands and hooks
    tuscany::oauth2::commands, tuscany::oauth2::registerHooks
};

}
