Apache module development by extending existing mod_basic_auth
This below mentioned step by step procedure help you to create apache module to protected your digital good.
Step 1: Prerequisite
1.1 Install apache2 webserver
sudo apt-get install apache2
1.2 Install apache compiler using the below mentioned command.
sudo apt-get install apache2-threaded-dev
1.3 Install latest libcurl package using the below mentioned command.
sudo apt-get install libcurl4-openssl-dev
Step 2: Create a simple apache module c file and compile it using the below mentioned command.
apxs2 -c mod_paypal_ec.c (for debian OS)
apxs -c mod_paypal_ec.c (for mac OS)
Step 3: Apache load config file
Create test_ec.load config file under /etc/apache2/mods-available
LoadFile /usr/lib/x86_64-linux-gnu/libcurl.so
LoadModule mod_test_ec /Users/csivakolundu/mod_test_ec/src/.libs/mod_test_ec.so
<Location /books>
AuthType EC
AuthName "Test EC"
Require valid-user
</Location>
Step 4: Apache config file
Create test_ec.conf config file under /etc/apache2/mods-available with all your application properties which are going to referred in your c file.
ApiUserName aaaaaa_1350334651_biz_api1.paypal.com
ApiPassword 1350334729
Step 5: Enabling mod_test_ec module
Create symbolic link for test_ec.load and test_ec.conf files under /etc/apache2/mods-enable/ folder.
Step 6: Apache virtual host
Update apache virtual host file from /etc/apache2/sites-enabled/ with the following changes.
<IfModule mod_paypal_ec>
<Location /books>
AuthType ExpressCheckout
AuthName "PayPal ExpressCheckout"
Require valid-user
</Location>
</IfModule>
Step 7: Simple mod_test_ec.c file.
Simple apache c file to protected your digital good available under /var/www/books folder. Auth check is not done in the below example.
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "http_request.h"
#include "util_script.h"
#include "mod_auth.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <curl/easy.h>
typedef struct {
const char* endPoint;
const char* userName;
const char* password;
const char* ecType;
}app_config;
static app_config config;
int ec_handler(request_rec *r);
void register_hooks(apr_pool_t *p);
int sendFile(request_rec *r, apr_table_t *data);
static int authenticate_user(request_rec *r);
const char *api_endpoint_handler(cmd_parms *cmd, void *cfg, const char *arg)
{
config.endPoint= arg;
return NULL;
}
const char *api_username_handler(cmd_parms *cmd, void *cfg, const char *arg)
{
config.userName= arg;
return NULL;
}
const char *apr_password_handler(cmd_parms *cmd, void *cfg, const char *arg)
{
config.password= arg;
return NULL;
}
const char *ec_type_handler(cmd_parms *cmd, void *cfg, const char *arg)
{
config.ecType = arg;
return NULL;
}
static const command_rec ec_directives[] = {
AP_INIT_TAKE1("ApiEndPoint", api_endpoint_handler, NULL, RSRC_CONF, "The mod_paypal_ec application configuration file"),
AP_INIT_TAKE1("ApiUserName", api_username_handler, NULL, RSRC_CONF, "The mod_paypal_ec application configuration file"),
AP_INIT_TAKE1("ApiPassword", apr_password_handler, NULL, RSRC_CONF, "The mod_paypal_ec application configuration file"),
AP_INIT_TAKE1("ECType", ec_type_handler, NULL, RSRC_CONF, "The mod_paypal_ec application configuration file"),
{NULL}
};
module AP_MODULE_DECLARE_DATA mod_test_ec =
{
STANDARD20_MODULE_STUFF,
NULL,
NULL,
NULL,
NULL,
ec_directives,
register_hooks
};
void register_hooks(apr_pool_t *p) {
ap_hook_check_user_id(authenticate_user,NULL,NULL,APR_HOOK_MIDDLE);
}
static int authenticate_user(request_rec *r)
{
const char *sent_user, *sent_pw, *current_auth;
int res;
authn_status auth_result;
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Authenticate_user starting....");
current_auth = ap_auth_type(r);
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Current auth %s", current_auth);
if (!current_auth || strcasecmp(current_auth, "EC")) {
return DECLINED;
}
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "After auth check");
/* We need an authentication realm. */
if (!ap_auth_name(r)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR,
0, r, "need AuthName: %s", r->uri);
return HTTP_INTERNAL_SERVER_ERROR;
}
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "After auth name check");
r->ap_auth_type = "EC";
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Calling ec handler");
return ec_handler(r);
}
int ec_handler(request_rec *r)
{
char *next = r->uri;
char *uri = r->unparsed_uri;
if ( r->method_number != M_GET ) {
return HTTP_METHOD_NOT_ALLOWED ;
}
status = sendFile(r, data);
if(status > 0) {
return HTTP_INTERNAL_SERVER_ERROR;
}
return OK;
}
int sendFile(request_rec *r, apr_table_t *data) {
int status = 0;
apr_file_t *fd;
apr_size_t sz;
apr_status_t rv;
if (r->filename == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,"Incomplete request_rec!");
status = 1;
return status;
}
char* ext = strrchr(r->filename, '.') ;
if(strcmp(ext, ".pdf") ==0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Downloading pdf file");
ap_set_content_type(r, "application/pdf");
} else {
ap_set_content_type(r, "application/pdf");
}
ap_set_content_length(r, r->finfo.size);
//ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "File size : %zu", r-> finfo.size);
if (r->finfo.mtime) {
char *datestring = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
apr_rfc822_date(datestring, r->finfo.mtime);
apr_table_setn(r->headers_out, "Last-Modified", datestring);
}
rv = apr_file_open(&fd, r->filename,
APR_READ|APR_SHARELOCK|APR_SENDFILE_ENABLED,
APR_OS_DEFAULT, r->pool);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,"can't open %s", r->filename);
return HTTP_NOT_FOUND ;
}
ap_send_fd(fd, r, 0, r->finfo.size, &sz);
apr_file_close(fd);
return status;
}
Step 8: For Mac only.
4.1 Update the libcurl.so path from paypal_ec.load to "LoadFile /usr/lib/libcurl.4.dylib"
4.2 Create Simbolic link like below.
$> cd /Applications/Xcode.app/Contents/Developer/Toolchains/
$> sudo ln -s XcodeDefault.xctoolchain/ OSX10.8.xctoolchain