<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Roberto Moutinho</title>
	<atom:link href="http://robertomoutinho.com.br/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://robertomoutinho.com.br/blog</link>
	<description>Web Operations ( Sysadmin and DBA )</description>
	<lastBuildDate>Tue, 06 Sep 2011 01:48:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Using Memcached + MySQL + Inline C ( Varnish Cache ) to authenticate basic keys ( Restfull API ).</title>
		<link>http://robertomoutinho.com.br/blog/using-memcached-mysql-inline-c-varnish-cache-to-authenticate-basic-keys-restfull-api/</link>
		<comments>http://robertomoutinho.com.br/blog/using-memcached-mysql-inline-c-varnish-cache-to-authenticate-basic-keys-restfull-api/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 18:24:38 +0000</pubDate>
		<dc:creator>administrador</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[inline c]]></category>
		<category><![CDATA[libmemcache]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[restfull]]></category>
		<category><![CDATA[varnish]]></category>
		<category><![CDATA[web scraping]]></category>

		<guid isPermaLink="false">http://robertomoutinho.com.br/blog/?p=50</guid>
		<description><![CDATA[After reading Dr. Carter post about blocking web scraping with Varnish Cache inline C code&#8230; I&#8217;ve had the ideia do authenticate user of a Restfull API (basic http auth) using the same tools + mysql. I won&#8217;t cover the varnish cache configuration&#8230; just the inline C code I&#8217;ve used to do the job. /* Import [...]]]></description>
			<content:encoded><![CDATA[            <script type="text/javascript" src="http://robertomoutinho.com.br/blog/wp-content/plugins/wordpress-code-snippet/scripts/shBrushCpp.js"></script>
<p>After reading <a href="http://drcarter.info/2010/04/how-fighting-against-scraping-using-varnish-vcl-inline-c-memcached/">Dr. Carter post</a> about blocking web scraping with Varnish Cache inline C code&#8230;</p>
<p>I&#8217;ve had the ideia do authenticate user of a Restfull API (basic http auth) using the same tools + mysql.</p>
<p>I won&#8217;t cover the varnish cache configuration&#8230; just the inline C code I&#8217;ve used to do the job.</p>
<p><pre class="brush: cpp">/* Import this modules in the begining of your VCL code */

C{
#include &lt;string.h&gt;
#include &lt;/usr/local/include/libmemcached/memcached.h&gt;
#include &lt;syslog.h&gt;
#include &lt;/usr/include/mysql/mysql.h&gt;
#include &lt;stdio.h&gt;
}C

/* Insert the code on your vcl_recv wherever you want (as longs as your requests passes thru the code) */

C{
      memcached_server_st *servers = NULL;
      memcached_st *memc;
      memcached_return_t rc;
	/* 
	I use a combination of &quot;KEY_IP&quot; to count the requests.
	So change the next lines to adapt the key used in memcached to your needs. 
	*/
      char key[50];
      strcat(key, VRT_GetHdr(sp, HDR_REQ, &quot;\012X-API-Key:&quot;));
      strcat(key, &quot;_&quot;);
      strcat(key, VRT_IP_string(sp, VRT_r_client_ip(sp)));

      memc= memcached_create(NULL);
      servers= memcached_server_list_append(servers, &quot;localhost&quot;, 11211, &amp;rc);
      rc= memcached_server_push(memc, servers);
      syslog(LOG_INFO, &quot;Memcached connection = %s&quot;,memcached_strerror(memc, rc));
	/* If connection to memcached was succesfull we'll try to decrement this key. */
      if (rc == MEMCACHED_SUCCESS) {
	rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 10);
        uint64_t intval;
        rc= memcached_decrement(memc, key, strlen(key), (uint64_t)1, &amp;intval);

        if (rc != MEMCACHED_SUCCESS) {
	/* 
	If decrement has failed we need to authenticate the key on MySQL (which means that the key has not been verified before).
	Remember to create a view (for safety reasons the mysql user is only privileged to use the created view) and to add an index on your table (for a fast read).
	*/
          syslog(LOG_INFO, &quot;Key found in Memcached ? = %s&quot;,memcached_strerror(memc, rc));
	  MYSQL     *conn;
	  MYSQL_RES *res;
	  MYSQL_ROW  row;
	  char rows;
	  char query[200];
	  sprintf(query, &quot;select request-limit from view where key = '%s'&quot; ,VRT_GetHdr(sp, HDR_REQ, &quot;\012X-API-Key:&quot;));
	  conn = mysql_init(NULL);
	  if (mysql_real_connect (conn,&quot;localhost&quot;,&quot;user&quot;,&quot;password&quot;,&quot;database_name&quot;,0,NULL,0) != NULL){
	    mysql_real_query(conn,query,strlen(query));
	    res = mysql_store_result(conn);
	    row = mysql_fetch_row(res);

	    if (row) {
		  	syslog(LOG_INFO, &quot;Result != NULL&quot;);
			char *limit = row[0];
			syslog(LOG_INFO,&quot;Key found in MySQL with %s requests total.&quot;,limit);
			rc= memcached_set(memc, key, strlen(key), limit, strlen(limit), (time_t)3600, (uint32_t)0);
			syslog(LOG_INFO, &quot;Key %s stored in Memcached ? = %s&quot;,key,memcached_strerror(memc, rc));
			/*
			If the Key has been found on database we collect the request limit and store it together with the key.
			We also set a 1 hour limit for this memcached object (3600) and log the response code from memcached.
			*/
	    } else {
 			 syslog(LOG_INFO, &quot;Key: %s not found in MySQL.&quot;,VRT_GetHdr(sp, HDR_REQ, &quot;\012X-API-Key:&quot;));
	                 VRT_error(sp, 401, &quot;Unauthorized.&quot;);
        	         VRT_done(sp, VCL_RET_ERROR);
			/* The provided key was not found on the database. Return a &quot;401 Unauthorized&quot; code. */
	    }
          } else {
		    syslog(LOG_INFO,&quot;MySQL: Error %u (%s)&quot;,mysql_errno (conn), mysql_error (conn));
                    VRT_error(sp, 500, &quot;Internal server error.&quot;);
                    VRT_done(sp, VCL_RET_ERROR);
			/* In case of a database connection problem we return a &quot;500 Internal server error&quot; code. */
          }
    	  mysql_free_result(res);
	  mysql_close(conn);
        }
        else {
	  syslog(LOG_INFO, &quot;Key found in Memcached ? = %s&quot;,memcached_strerror(memc, rc));
          syslog(LOG_INFO, &quot;Decrement key %s in Memcached ? = %s&quot;,key,memcached_strerror(memc, rc));

          if (intval &lt; 1) {
	    syslog(LOG_INFO, &quot;Key %s limit exceeded. Client Ip = %s&quot;,VRT_GetHdr(sp, HDR_REQ, &quot;\012X-API-Key:&quot;),VRT_IP_string(sp, VRT_r_client_ip(sp)));
            VRT_error(sp, 403, &quot;Forbidden&quot;);
            VRT_done(sp, VCL_RET_ERROR);
		/* If the decremented result from memcached is lower than &quot;1&quot; we return a &quot;403 Forbidden&quot; code. Client requests maxed-out. */
          }
        }
      }
      memcached_free(memc);
      memcached_server_list_free(servers);
}C
</pre></p>
<p>and to my varnish daemon startup I&#8217;ve added:</p>
<p>-p &#8216;cc_command=exec cc -fpic -shared -Wl,-x -L/usr/local/include/libmemcached/memcached.h -L/usr/lib64/mysql -lmysqlclient -lmemcached -o %o %s&#8217;</p>
<p>&nbsp;</p>
<p>ps1: you&#8217;ll need mysql-client &#038; mysql-devel package and also libmemcached.<br />
ps2: A thank you note to the varnish mailing list which assisted me thru the entire process.</p>
]]></content:encoded>
			<wfw:commentRss>http://robertomoutinho.com.br/blog/using-memcached-mysql-inline-c-varnish-cache-to-authenticate-basic-keys-restfull-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

