Abhi's Experiments

Its a place to write about my professional experience and experiments

Apache External Authentication

I have created a web application which is a middleware situated between the mobile app and the webservice provider. Some requests should be handled by the middleware and some other requests should be forwarded to the webservice provider.

We can add apache proxy to forward the requests to the webservice provider. But before forwarding the requests it should be validated. If we are validating from the application then we can’t use the apache proxy, so the validation has to be implemented within apache.

There is a custom module for apache to do this kind of external authentication called mod-auth-external. Where you can mention the path of an external authentication file. Whenever apache gets a request it will execute the validation file and based on the response (true/false) from validation file apache either continue with the request or return unauthorized.

Sample virtual_host.conf file:

LoadModule authnz_external_module modules/mod_authnz_external.so
<VirtualHost *:80>
DocumentRoot "/var/www/application_name"
ServerName application_name.com
AddExternalAuth auth /var/www/application_name/validate.php
SetExternalAuthMethod auth environment
<Directory "/var/www/application_name">
   Options Indexes +FollowSymLinks MultiViews +ExecCGI
   AllowOverride None
   Order allow,deny
   Allow from all
</Directory>
<Location ~ "^/api/(.*)$">
   AuthName "AppName"
   AuthType Basic
   AuthBasicProvider external
   AuthExternal auth
   require valid-user
</Location>
ProxyRequests Off
ProxyPreserveHost On
ProxyPass /api/ https://192.168.1.200/Webserver/
ProxyPassReverse /api/ https://192.168.1.200/Webserver/
<Proxy *>
   Order deny,allow
   Allow from all
</Proxy>
</VirtualHost>

Sample external authentication file (validate.php):

#!/usr/bin/php
<?php
$host = "127.0.0.1";
$user = "user";
$password = "password";
$database = "database";
$link = mysql_connect($host, $user, $password);
$selected = mysql_select_db($database, $link);
$username = getenv('USER');
$password = getenv("PASS");
$sql = "SELECT * FROM table_name WHERE username= '$username' AND password = '$password' AND status = 1";
$result = mysql_query($sql, $link);
$count = mysql_num_rows($result);
if ($count > 0) {
  exit(0);
} else {
  exit(1);
}  
?> 

comments...

Distributed Job Processing with Celery

Recently I got a task to create a job processing application. The application will fetch the data from an API, parse the data, and create jobs for the data.

The job is to record a livestream using ffmpeg. There will be multiple jobs running simultaneously, so the idea is to create a distributed job processing application.

We have selected Celery as it is an asynchronous distributed task queue written in Python. Also we have used RabbitMQ as the message broker.

We have designed the infrastructure with the application running on multiple instances. One instance will be the Celery master where we execute the script to fetch data from API, parse the data, add jobs to the queue. Other instances will be running the Celery worker with the same RabbitMQ server as message broker.

app = Celery('tasks', backend='amqp://guest@192.168.1.3//', 
                       broker='amqp://guest@192.168.1.3//')

We are using a cron job in the Celery master to execute the script periodically. The Celery master and the Celery workers will be pointing to the same RabbitMQ server, so whenever a new job is added to the queue it will be assigned to a worker.

We are also using Flower: a celery monitoring tool in Celery master to check the status of the jobs and for other monitoring.

comments...

Front End App CORS issue in development environment

When you are developing a Front End Application or Single page application using Backbone.js, Angular.js or any other MV* frameworks, you might have faced the issue with CORS. You will face this issue if you are accessing the hosted web services (API) from your development environment because the domains are different.

We can solve the CORS issue in different ways. First method is JSONP. To implement JSONP you need the access to modify the web services. Because to implement the JSONP the web service has to return the json data wrapped in a function. You can do this only if you have the rights to change the web service.

If you don’t have the right to change the web services, the next method to solve CORS issue is to set the Header Access Control Allow Origin in the server. You can set the Origin to multiple domains to support access from multiple domains. For this you need access to server to modify the apache/nginx virtual host configuration. But what if you don’t have access to the server at all?

The next and the best solution is to implement reverse proxy in the development environment. Here is a sample virtual host file which has reverse proxy implemented:

<VirtualHost *:80> 
    ServerName front_end_app.abhilash-desktop.com 
    DocumentRoot /home/abhilash/Projects/front_end_app/public 
    <Directory /home/abhilash/Projects/front_end_app/public> 
       AllowOverride all    
       Options -MultiViews  
    </Directory> 
       
    LoadModule proxy_module modules/mod_proxy.so 
    ProxyRequests Off 
  
    <Proxy *> 
      Order deny,allow 
      Allow from all 
    </Proxy> 
  
    ProxyPass /api http://abhidsm.com/api 
    ProxyPassReverse /api http://abhidsm.com/api 
             
ErrorLog /var/log/apache2/error.log 
               
# Possible values include: debug, info, notice, warn, error, crit, 
# alert, emerg. 
LogLevel warn 
     
CustomLog /var/log/apache2/access.log combined 
</VirtualHost>

From your app if you start accessing the /api URL it will be accessed from the proxy URL. I think this is the easiest and best method to solve the CORS issue in development environment.

comments...