static int set_session_cookie(request_rec *r, modauthopenid_config *s_cfg, opkele::params_t& params, std::string identity) {
  // now set auth cookie, if we're doing session based auth
  std::string session_id, hostname, path, cookie_value, redirect_location, args;
  if(s_cfg->cookie_path != NULL) 
    path = std::string(s_cfg->cookie_path); 
  else 
    modauthopenid::base_dir(std::string(r->uri), path); 
  modauthopenid::make_rstring(32, session_id);
  modauthopenid::make_cookie_value(cookie_value, std::string(s_cfg->cookie_name), session_id, path, s_cfg->cookie_lifespan); 
  APDEBUG(r, "Setting cookie after authentication of user %s", identity.c_str());
  apr_table_set(r->err_headers_out, "Set-Cookie", cookie_value.c_str());
  hostname = std::string(r->hostname);

  // save session values
  modauthopenid::SessionManager sm(std::string(s_cfg->db_location));
  sm.store_session(session_id, hostname, path, identity, s_cfg->cookie_lifespan);
  sm.close();

  opkele::params_t ext_params;
  modauthopenid::get_extension_params(ext_params, params);
  modauthopenid::remove_openid_vars(params);
  modauthopenid::merge_params(ext_params, params);
  args = params.append_query("", "").substr(1);
  if(args.length() == 0)
    r->args = NULL;
  else
    apr_cpystrn(r->args, args.c_str(), 1024);
  full_uri(r, redirect_location, s_cfg);
  return modauthopenid::http_redirect(r, redirect_location);
};
static int start_authentication_session(request_rec *r, modauthopenid_config *s_cfg, opkele::params_t& params,
                                        std::string& return_to, std::string& trust_root) {
    // remove all openid GET query params (openid.*) - we don't want that maintained through
    // the redirection process.  We do, however, want to keep all other GET params.
    // also, add a nonce for security
    std::string identity = s_cfg->use_single_idp
                           ? s_cfg->single_idp_url
                           : params.get_param("openid_identifier");
    APDEBUG(r, "identity = %s, use_single_idp = %s", identity.c_str(), s_cfg->use_single_idp ? "true" : "false");
    // pull out the extension parameters before we get rid of openid.*
    opkele::params_t ext_params;
    modauthopenid::get_extension_params(ext_params, params);
    modauthopenid::remove_openid_vars(params);

    // if attribute directives are set, add AX stuff to extension params
    if(s_cfg->use_ax)
    {
        ext_params["openid.ns." DEFAULT_AX_NAMESPACE_ALIAS] = AX_NAMESPACE;
        ext_params["openid." DEFAULT_AX_NAMESPACE_ALIAS ".mode"] = "fetch_request";
        std::string required = "";
        bool first_alias = true;
        for(int i = 0; i < s_cfg->ax_attrs->nelts; ++i) {
            std::string alias = APR_ARRAY_IDX(s_cfg->ax_attrs, i, const char *);
            std::string uri = apr_table_get(s_cfg->ax_attr_uris, alias.c_str());
            ext_params["openid." DEFAULT_AX_NAMESPACE_ALIAS ".type." + alias] = uri;
            if(first_alias) {
                first_alias = false;
            } else {
                required += ',';
            }
            required += alias;
        }
        ext_params["openid." DEFAULT_AX_NAMESPACE_ALIAS ".required"] = required;
    }
static int start_authentication_session(request_rec *r, modauthopenid_config *s_cfg, opkele::params_t& params, 
					std::string& return_to, std::string& trust_root) {
  // remove all openid GET query params (openid.*) - we don't want that maintained through
  // the redirection process.  We do, however, want to keep all aother GET params.
  // also, add a nonce for security 
  std::string identity = params.get_param("openid_identifier");
  // pull out the extension parameters before we get rid of openid.*
  opkele::params_t ext_params;
  modauthopenid::get_extension_params(ext_params, params);
  modauthopenid::remove_openid_vars(params);

  // add a nonce and reset what return_to is
  std::string nonce, re_direct;
  modauthopenid::make_rstring(10, nonce);
  modauthopenid::MoidConsumer consumer(std::string(s_cfg->db_location), nonce, return_to);    
  params["modauthopenid.nonce"] = nonce;
  full_uri(r, return_to, s_cfg, true);
  return_to = params.append_query(return_to, "");

  // get identity provider and redirect
  try {
    consumer.initiate(identity);
    opkele::openid_message_t cm; 
    re_direct = consumer.checkid_(cm, opkele::mode_checkid_setup, return_to, trust_root).append_query(consumer.get_endpoint().uri);
    re_direct = ext_params.append_query(re_direct, "");
  } catch (opkele::failed_xri_resolution &e) {
    consumer.close();
    return show_input(r, s_cfg, modauthopenid::invalid_id);
  } catch (opkele::failed_discovery &e) {
    consumer.close();
    return show_input(r, s_cfg, modauthopenid::invalid_id);
  } catch (opkele::bad_input &e) {
    consumer.close();
    return show_input(r, s_cfg, modauthopenid::invalid_id);
  } catch (opkele::exception &e) {
    consumer.close();
    APERR(r, "Error while fetching idP location: %s", e.what());
    return show_input(r, s_cfg, modauthopenid::no_idp_found);
  }
  consumer.close();
  if(!is_trusted_provider(s_cfg , re_direct, r) || is_distrusted_provider(s_cfg, re_direct, r))
    return show_input(r, s_cfg, modauthopenid::idp_not_trusted);
  return modauthopenid::http_redirect(r, re_direct);
};
static int validate_authentication_session(request_rec *r, modauthopenid_config *s_cfg, opkele::params_t& params, std::string& return_to) {
  // make sure nonce is present
  if(!params.has_param("modauthopenid.nonce")) 
    return show_input(r, s_cfg, modauthopenid::invalid_nonce);

  modauthopenid::MoidConsumer consumer(std::string(s_cfg->db_location), params.get_param("modauthopenid.nonce"), return_to);
  try {
    consumer.id_res(modauthopenid::modauthopenid_message_t(params));
    
    // if no exception raised, check nonce
    if(!consumer.session_exists()) {
      consumer.close();
      return show_input(r, s_cfg, modauthopenid::invalid_nonce); 
    }

    // if we should be using a user specified auth program, run it to see if user is authorized
    if(s_cfg->use_auth_program) {
      std::string username = consumer.get_claimed_id();
      std::string progname = std::string(s_cfg->auth_program);
      modauthopenid::exec_result_t eresult = modauthopenid::exec_auth(progname, username);
      if(eresult != modauthopenid::id_accepted) {
	std::string error = modauthopenid::exec_error_to_string(eresult, progname, username);
	APERR(r, "Error in authentication: %s", error.c_str());	
	consumer.close();
	return show_input(r, s_cfg, modauthopenid::unauthorized);       
      } else {
	APDEBUG(r, "Authenticated %s using %s", username.c_str(), progname.c_str());	
      }
    }

    // Make sure that identity is set to the original one given by the user (in case of delegation
    // this will be different than openid_identifier GET param
    std::string identity;
    if (s_cfg->sso_url && s_cfg->sso_user_base) {
	std::string c_identity = consumer.get_claimed_id();
	if (strstr(c_identity.c_str(), s_cfg->sso_user_base) == c_identity.c_str()) {
		identity = strdup(c_identity.c_str() + strlen(s_cfg->sso_user_base));
	} else {
		std::string error = "SSOUserBase didn't match in the identity";
		APERR(r, "Error in authentication: %s", error.c_str());	
		consumer.close();
		return show_input(r, s_cfg, modauthopenid::unauthorized);       
	}
    } else
    	identity = consumer.get_claimed_id();

    consumer.kill_session();
    consumer.close();

    if(s_cfg->use_cookie) 
      return set_session_cookie(r, s_cfg, params, identity);
      
    // if we're not setting cookie - don't redirect, just show page
    APERR(r, "Setting REMOTE_USER to %s", identity.c_str());
    r->user = apr_pstrdup(r->pool, identity.c_str());
    return DECLINED;
  } catch(opkele::exception &e) {
    APERR(r, "Error in authentication: %s", e.what());
    consumer.close();
    return show_input(r, s_cfg, modauthopenid::unspecified);
  }
};