Showing posts with label httpd. Show all posts
Showing posts with label httpd. Show all posts

Monday, 22 November 2010

EEE: erlang inets http authentication with mnesia

Again, I am using R13B04 (erts-5.7.5) on Fedora 13.

Unfortunately erlang's inets http server only performs Basic authentication.  So I would only authenticate over https, like I've shown here.  Setting up erlang inets for SSL can be tricky depending on what you want to do.  One important gotcha is detailed in this post.

Create Tables

First, your application must create some mnesia tables for authentication. For this you need the record definitions.  The documentation for mod_auth says to add the following line to your module.

-include("mod_auth.hrl").

erlc failed to find the file, so I found it in "/usr/lib64/erlang/lib/inets-5.3/src/" and copied it to my project manually.

Creating the tables is no different to the documentation

mnesia:create_schema([node()]),
    mnesia:start(),
    mnesia:create_table(httpd_user,
                        [{type, bag},
                         {disc_copies, [node()]},
                         {attributes, record_info(fields, 
                                                  httpd_user)}]),
    mnesia:create_table(httpd_group,
                        [{type, bag},
                         {disc_copies, [node()]},          
                         {attributes, record_info(fields, 
                                                  httpd_group)}]),
    mnesia:wait_for_tables([httpd_user, httpd_group], 60000).

The documentation says this is a naive implementation, a trick I have used is to catch the output of mnesia:create_schema.  Ok means that the schema didn't exist before and the tables have to be created.  If there is a better way, I'd like to hear it.

Add user and group

Next, adding a user and group to the database, I use the mod_auth functions

true = mod_auth:add_user("superuser", "password", "Super User", 443, "/test"),
true = mod_auth:add_group_member("users", "superuser", 443, "/test").

Configuring for Authentication

Below is the next version of my "443.conf" file which includes the necessary configuration for authentication.

[
 {modules, [
  mod_alias, 
  mod_auth, 
  mod_esi, 
  mod_actions, 
  mod_cgi, 
  mod_dir, 
  mod_get, 
  mod_head, 
  mod_log, 
  mod_disk_log
 ]},
 {port,443},
 {server_name,"localhost.localdomain"},
 {server_root,"log"},
 {document_root,"secure"},
 {erl_script_alias, {"/test", [test]}},
 {directory, 
  {"/test", [
   {auth_name, "Data Server"}, 
   {allow_from, all}, 
   {auth_type, mnesia},
   {require_group, ["users"]}
  ]}
 },
 {socket_type, ssl},
 {ssl_certificate_file, "localhost.pem"},
 {error_log, "error.log"},
 {security_log, "security.log"},
 {transfer_log, "transfer.log"},
 {mime_types,[
  {"html","text/html"},
  {"css","text/css"},
  {"js","application/x-javascript"}
 ]}
]. 

To access my test esi module, I now need a to use a password.

EEE: Configuring Erlang inets

Erlang's built in web server (part of inets) has a number of quirks, first one I came across is listing the server modules in a specific order in the configuration file.  I am using R13B04 erts-5.7.5 on Fedora 13 for this post.

Much of this came from this stackoverflow question.   I've almost copied it completely except for a few details below.

Here is a complete configuration file example. (8080.conf)

[
 {modules, [
  mod_alias, 
  mod_auth, 
  mod_esi, 
  mod_actions, 
  mod_cgi, 
  mod_dir, 
  mod_get, 
  mod_head, 
  mod_log, 
  mod_disk_log
 ]},
 {port,8080},
 {server_name,"localhost.localdomain"},
 {server_root,"log"},
 {document_root,"www"},
 {erl_script_alias, {"/test", [test]}},
 {error_log, "error.log"},
 {security_log, "security.log"},
 {transfer_log, "transfer.log"},
 {mime_types,[
  {"html","text/html"},
  {"css","text/css"},
  {"js","application/x-javascript"}
 ]}
].

Here is how to start inets using the configuration file.

 inets:start(),
 inets:start(httpd, [{proplist_file, "8080.conf"}]). 

Make sure that both "www" and "log" directories are there otherwise it won't work either.  If you put a test file in the "www" directory, opening http://localhost:8080/test.html will download it.

A few things didn't work, so I wouldn't bother trying this
  1.  Trying to add extra configuration items before or after proplist_file when calling inets:start.  I tried to specify the port dynamically in this fashion, but it didn't work. Looking at the source might help me work out why.
  2. Switching port 8080 to a port < 1024.  Linux doesn't let you do this without some extra trickery.  I'm investigating how to get around this.