"Fossies" - the Fresh Open Source Software Archive

Member "mod_auth_openid-0.8/src/MoidConsumer.cpp" (23 Oct 2013, 13872 Bytes) of package /linux/www/apache_httpd_modules/mod_auth_openid-0.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "MoidConsumer.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2 Copyright (C) 2007-2010 Butterfat, LLC (http://butterfat.net)
    3 
    4 Permission is hereby granted, free of charge, to any person
    5 obtaining a copy of this software and associated documentation
    6 files (the "Software"), to deal in the Software without
    7 restriction, including without limitation the rights to use,
    8 copy, modify, merge, publish, distribute, sublicense, and/or sell
    9 copies of the Software, and to permit persons to whom the
   10 Software is furnished to do so, subject to the following
   11 conditions:
   12 
   13 The above copyright notice and this permission notice shall be
   14 included in all copies or substantial portions of the Software.
   15 
   16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   18 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   20 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   21 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   23 OTHER DEALINGS IN THE SOFTWARE.
   24 
   25 Created by bmuller <bmuller@butterfat.net>
   26 */
   27 
   28 #include "mod_auth_openid.h"
   29 
   30 namespace modauthopenid {
   31   using namespace std;
   32   using namespace opkele;
   33  
   34   MoidConsumer::MoidConsumer(const string& storage_location, const string& _asnonceid, const string& _serverurl) :
   35                              asnonceid(_asnonceid), serverurl(_serverurl), is_closed(false), endpoint_set(false), normalized_id("") {
   36     // open db file as user rw only
   37     ::mode_t old = umask(S_IRWXO|S_IRWXG);
   38     int rc = sqlite3_open(storage_location.c_str(), &db);
   39     umask(old);
   40     if(!test_result(rc, "problem opening database"))
   41       return;
   42     sqlite3_busy_timeout(db, 5000);
   43 
   44     string query = "CREATE TABLE IF NOT EXISTS authentication_sessions "
   45       "(nonce VARCHAR(255), uri VARCHAR(255), claimed_id VARCHAR(255), local_id VARCHAR(255), normalized_id VARCHAR(255), expires_on INT)";
   46     rc = sqlite3_exec(db, query.c_str(), 0, 0, 0);
   47     test_result(rc, "problem creating sessions table if it didn't exist already");
   48 
   49     query = "CREATE TABLE IF NOT EXISTS associations "
   50       "(server VARCHAR(255), handle VARCHAR(100), encryption_type VARCHAR(50), secret VARCHAR(30), expires_on INT)";
   51     rc = sqlite3_exec(db, query.c_str(), 0, 0, 0);
   52     test_result(rc, "problem creating associations table if it didn't exist already");
   53 
   54     query = "CREATE TABLE IF NOT EXISTS response_nonces "
   55       "(server VARCHAR(255), response_nonce VARCHAR(100), expires_on INT)";
   56     rc = sqlite3_exec(db, query.c_str(), 0, 0, 0);
   57     test_result(rc, "problem creating response_nonces table if it didn't exist already");
   58   };
   59 
   60 
   61   assoc_t MoidConsumer::store_assoc(const string& server,const string& handle,const string& type,const secret_t& secret,int expires_in) {
   62     debug("Storing association for \"" + server + "\" and handle \"" + handle + "\" in db");
   63     ween_expired();
   64 
   65     time_t rawtime;
   66     time (&rawtime);
   67     int expires_on = rawtime + expires_in;
   68 
   69     const char *query = "INSERT INTO associations (server, handle, secret, expires_on, encryption_type) VALUES(%Q,%Q,%Q,%d,%Q)";
   70     char *sql = sqlite3_mprintf(query, 
   71                 server.c_str(), 
   72                 handle.c_str(), 
   73                 util::encode_base64(&(secret.front()),secret.size()).c_str(),
   74                 expires_on,
   75                 type.c_str());
   76     int rc = sqlite3_exec(db, sql, 0, 0, 0);
   77     sqlite3_free(sql);
   78     test_result(rc, "problem storing association in associations table");
   79 
   80     return assoc_t(new association(server, handle, type, secret, expires_on, false));
   81   };
   82 
   83   assoc_t MoidConsumer::retrieve_assoc(const string& server, const string& handle) {
   84     ween_expired();
   85     debug("looking up association: server = " + server + " handle = " + handle);
   86 
   87     const char *query = "SELECT server,handle,secret,expires_on,encryption_type FROM associations WHERE server=%Q AND handle=%Q LIMIT 1";
   88     char *sql = sqlite3_mprintf(query, server.c_str(), handle.c_str());
   89     int nr, nc;
   90     char **table;
   91     int rc = sqlite3_get_table(db, sql, &table, &nr, &nc, 0);
   92     sqlite3_free(sql);
   93     test_result(rc, "problem fetching association");
   94     if(nr ==0) {
   95       debug("could not find server \"" + server + "\" and handle \"" + handle + "\" in db.");
   96       sqlite3_free_table(table);
   97       throw failed_lookup(OPKELE_CP_ "Could not find association.");
   98     }
   99     // resulting row has table indexes: 
  100     // server  handle  secret  expires_on  encryption_type
  101     // 5       6       7       8           9
  102     secret_t secret; 
  103     util::decode_base64(table[7], secret);
  104     assoc_t result = assoc_t(new association(table[5], table[6], table[9], secret, strtol(table[8], 0, 0), false));
  105     sqlite3_free_table(table);
  106     return result;
  107   };
  108 
  109   void MoidConsumer::invalidate_assoc(const string& server,const string& handle) {
  110     debug("invalidating association: server = " + server + " handle = " + handle);
  111     char *query = sqlite3_mprintf("DELETE FROM associations WHERE server=%Q AND handle=%Q", server.c_str(), handle.c_str());
  112     int rc = sqlite3_exec(db, query, 0, 0, 0);
  113     sqlite3_free(query);
  114     test_result(rc, "problem invalidating assocation for server \"" + server + "\" and handle \"" + handle + "\"");
  115   };
  116 
  117   assoc_t MoidConsumer::find_assoc(const string& server) {
  118     ween_expired();
  119     debug("looking up association: server = " + server);
  120 
  121     const char *query = "SELECT server,handle,secret,expires_on,encryption_type FROM associations WHERE server=%Q LIMIT 1";
  122     char *sql = sqlite3_mprintf(query, server.c_str());
  123     int nr, nc;
  124     char **table;
  125     int rc = sqlite3_get_table(db, sql, &table, &nr, &nc, 0);
  126     sqlite3_free(sql);
  127     test_result(rc, "problem fetching association");
  128     if(nr==0) {
  129       debug("could not find handle for server \"" + server + "\" in db.");
  130       sqlite3_free_table(table);
  131       throw failed_lookup(OPKELE_CP_ "Could not find association.");
  132     } else {
  133       debug("found a handle for server \"" + server + "\" in db.");
  134     }
  135     // resulting row has table indexes: 
  136     // server  handle  secret  expires_on  encryption_type
  137     // 5       6       7       8           9
  138     secret_t secret; 
  139     util::decode_base64(table[7], secret);
  140     assoc_t result = assoc_t(new association(table[5], table[6], table[9], secret, strtol(table[8], 0, 0), false));
  141     sqlite3_free_table(table);
  142     return result;
  143   };
  144 
  145   bool MoidConsumer::test_result(int result, const string& context) {
  146     if(result != SQLITE_OK){
  147       string msg = "SQLite Error in MoidConsumer - " + context + ": %s\n";
  148       fprintf(stderr, msg.c_str(), sqlite3_errmsg(db));
  149       sqlite3_close(db);
  150       is_closed = true;
  151       return false;
  152     }
  153     return true;
  154   };
  155 
  156   void MoidConsumer::ween_expired() {
  157     time_t rawtime;
  158     time (&rawtime);
  159     char *query = sqlite3_mprintf("DELETE FROM associations WHERE %d > expires_on", rawtime);
  160     int rc = sqlite3_exec(db, query, 0, 0, 0);
  161     sqlite3_free(query);
  162     test_result(rc, "problem weening expired associations from table");
  163 
  164     query = sqlite3_mprintf("DELETE FROM authentication_sessions WHERE %d > expires_on", rawtime);
  165     rc = sqlite3_exec(db, query, 0, 0, 0);
  166     sqlite3_free(query);
  167     test_result(rc, "problem weening expired authentication sessions from table");
  168 
  169     query = sqlite3_mprintf("DELETE FROM response_nonces WHERE %d > expires_on", rawtime);
  170     rc = sqlite3_exec(db, query, 0, 0, 0);
  171     sqlite3_free(query);
  172     test_result(rc, "problem weening expired response nonces from table");
  173   };
  174 
  175 
  176   void MoidConsumer::check_nonce(const string& server, const string& nonce) {
  177     debug("checking nonce " + nonce);
  178     int nr, nc;
  179     char **table;
  180     char *query = sqlite3_mprintf("SELECT nonce FROM response_nonces WHERE server=%Q AND response_nonce=%Q", server.c_str(), nonce.c_str());
  181     int rc = sqlite3_get_table(db, query, &table, &nr, &nc, 0);
  182     sqlite3_free(query);
  183     if(nr != 0) {
  184       debug("found preexisting nonce - could be a replay attack");
  185       sqlite3_free_table(table);
  186       throw opkele::id_res_bad_nonce(OPKELE_CP_ "old nonce used again - possible replay attack");
  187     }
  188     sqlite3_free_table(table);
  189 
  190     // so, old nonce not found, insert it into nonces table.  Expiration time will be based on association
  191     int expires_on = find_assoc(server)->expires_in() + time(0);
  192     const char *sql = "INSERT INTO response_nonces (server,response_nonce,expires_on) VALUES(%Q,%Q,%d)";
  193     query = sqlite3_mprintf(sql, server.c_str(), nonce.c_str(), expires_on);
  194     rc = sqlite3_exec(db, query, 0, 0, 0);
  195     sqlite3_free(query);
  196     test_result(rc, "problem adding new nonce to resposne_nonces table");
  197   };
  198 
  199   bool MoidConsumer::session_exists() {
  200     char *query = sqlite3_mprintf("SELECT nonce FROM authentication_sessions WHERE nonce=%Q LIMIT 1", asnonceid.c_str());
  201     int nr, nc;
  202     char **table;
  203     int rc = sqlite3_get_table(db, query, &table, &nr, &nc, 0);
  204     sqlite3_free(query);
  205     test_result(rc, "problem fetching authentication session by nonce");
  206     bool exists = true;
  207     if(nr==0) {
  208       debug("could not find authentication session \"" + asnonceid + "\" in db.");
  209       exists = false;
  210     } 
  211     sqlite3_free_table(table);
  212     return exists;
  213   };
  214 
  215   void MoidConsumer::begin_queueing() {
  216     endpoint_set = false;
  217     char *query = sqlite3_mprintf("DELETE FROM authentication_sessions WHERE nonce=%Q", asnonceid.c_str());
  218     int rc = sqlite3_exec(db, query, 0, 0, 0);
  219     sqlite3_free(query);
  220     test_result(rc, "problem reseting authentication session");
  221   };
  222 
  223   void MoidConsumer::queue_endpoint(const openid_endpoint_t& ep) {
  224     if(!endpoint_set) {
  225       debug("Queueing endpoint " + ep.claimed_id + " : " + ep.local_id + " @ " + ep.uri);
  226       time_t rawtime;
  227       time (&rawtime);
  228       int expires_on = rawtime + 3600;  // allow nonce to exist for up to one hour without being returned
  229       const char *query = "INSERT INTO authentication_sessions (nonce,uri,claimed_id,local_id,expires_on) VALUES(%Q,%Q,%Q,%Q,%d)";
  230       char *sql = sqlite3_mprintf(query, asnonceid.c_str(), ep.uri.c_str(), ep.claimed_id.c_str(), ep.local_id.c_str(), expires_on);
  231       debug(string(sql));
  232       int rc = sqlite3_exec(db, sql, 0, 0, 0);
  233       sqlite3_free(sql);
  234       test_result(rc, "problem queuing endpoint");
  235       endpoint_set = true;
  236     }
  237   }
  238 
  239   const openid_endpoint_t& MoidConsumer::get_endpoint() const {
  240     debug("Fetching endpoint");
  241     char *query = sqlite3_mprintf("SELECT uri,claimed_id,local_id FROM authentication_sessions WHERE nonce=%Q LIMIT 1", asnonceid.c_str());
  242     int nr, nc;
  243     char **table;
  244     int rc = sqlite3_get_table(db, query, &table, &nr, &nc, 0);
  245     sqlite3_free(query);
  246     test_sqlite_return(db, rc, "problem fetching authentication session");
  247     if(nr==0) {
  248       debug("could not find an endpoint for authentication session \"" + asnonceid + "\" in db.");
  249       sqlite3_free_table(table);
  250       throw opkele::exception(OPKELE_CP_ "No more endpoints queued");
  251     } 
  252     // resulting row has table indexes:                                                   
  253     // uri   claimed_id   local_id
  254     // 3     4            5
  255     endpoint.uri = string(table[3]);
  256     endpoint.claimed_id = string(table[4]);
  257     endpoint.local_id = string(table[5]);
  258     sqlite3_free_table(table);
  259     return endpoint;
  260   };
  261 
  262   void MoidConsumer::next_endpoint() {
  263     debug("Clearing all session information - we're only storing one endpoint, can't get next one, cause we didn't store it.");
  264     char *query = sqlite3_mprintf("DELETE FROM authentication_sessions WHERE nonce=%Q", asnonceid.c_str());
  265     int rc = sqlite3_exec(db, query, 0, 0, 0);
  266     sqlite3_free(query);
  267     test_result(rc, "problem in next_endpoint()");
  268     endpoint_set = false;
  269   };
  270 
  271   void MoidConsumer::kill_session() {
  272     char *query = sqlite3_mprintf("DELETE FROM authentication_sessions WHERE nonce=%Q", asnonceid.c_str());
  273     int rc = sqlite3_exec(db, query, 0, 0, 0);
  274     sqlite3_free(query);
  275     test_result(rc, "problem killing session");
  276   };
  277 
  278   void MoidConsumer::set_normalized_id(const string& nid) {
  279     debug("Set normalized id to: " + nid);
  280     normalized_id = nid;
  281     char *query = sqlite3_mprintf("UPDATE authentication_sessions SET normalized_id=%Q WHERE nonce=%Q", normalized_id.c_str(), asnonceid.c_str());
  282     debug(string(query));
  283     int rc = sqlite3_exec(db, query, 0, 0, 0);
  284     sqlite3_free(query);
  285     test_result(rc, "problem settting normalized id");
  286   };
  287 
  288   const string MoidConsumer::get_normalized_id() const {
  289     if(normalized_id != "") {
  290       debug("getting normalized id - " + normalized_id);
  291       return normalized_id;
  292     }
  293     char *query = sqlite3_mprintf("SELECT normalized_id FROM authentication_sessions WHERE nonce=%Q LIMIT 1", asnonceid.c_str());
  294     int nr, nc;
  295     char **table;
  296     int rc = sqlite3_get_table(db, query, &table, &nr, &nc, 0);
  297     sqlite3_free(query);
  298     test_sqlite_return(db, rc, "problem fetching authentication session");
  299     if(nr==0) {
  300       debug("could not find an normalized_id for authentication session \"" + asnonceid + "\" in db.");
  301       sqlite3_free_table(table);
  302       throw opkele::exception(OPKELE_CP_ "cannot get normalized id");
  303     } 
  304     normalized_id = string(table[1]);
  305     sqlite3_free_table(table);  
  306     debug("getting normalized id - " + normalized_id);
  307     return normalized_id;
  308   };
  309 
  310   const string MoidConsumer::get_this_url() const {
  311     return serverurl;
  312   };
  313 
  314   // This is a method to be used by a utility program, never the apache module
  315   void MoidConsumer::print_tables() {
  316     ween_expired();
  317     print_sqlite_table(db, "authentication_sessions");
  318     print_sqlite_table(db, "response_nonces");
  319     print_sqlite_table(db, "associations");
  320   };
  321 
  322   void MoidConsumer::close() {
  323     if(is_closed)
  324       return;
  325     is_closed = true;
  326     test_result(sqlite3_close(db), "problem closing database");
  327   };
  328 }
  329 
  330 
  331