# mod_auth

### MODULE

mod_auth

### MODULE SUMMARY

User authentication using text files, dets or mnesia database.

### DESCRIPTION

This module provides for basic user authentication using textual files, dets databases as well as mnesia databases. The following config directives are supported:

- <Directory>
- AuthDBType
- AuthAccessPassword
- AuthUserFile
- AuthGroupFile
- AuthName
- allow
- deny
- require

The Directory config directive is central to be able to restrict access to certain areas of the server. Please read about the Directory config directive.

### DIRECTIVE: "Directory"

Syntax: `<Directory` regexp-filename`>`
Default: - None -
Module: mod_auth(3)
Related: allow, deny, AuthAccessPassword AuthUserFile, AuthGroupFile, AuthName, require

`<Directory>` and </Directory> are used to enclose a group of directives which applies only to the named directory and sub-directories of that directory. `regexp-filename` is an extended regular expression (See `regexp(3)`). For example:

    <Directory /usr/local/httpd[12]/htdocs>
         AuthAccessPassword sOmEpAsSwOrD
         AuthDBType plain
         AuthName My Secret Garden
         AuthUserFile /var/tmp/server_root/auth/user
         AuthGroupFile /var/tmp/server_root/auth/group
         require user ragnar edward
         require group group1
         allow from 123.145.244.5
    </Directory>

If multiple directory sections match the directory (or its parents), then the directives are applied with the shortest match first. For example if you have one directory section for `garden/` and one for `garden/flowers`, the `garden/` section matches first.

### DIRECTIVE: "AuthDBType"

Syntax: `AuthDBType` plain | dets | mnesia
Default: - None -
Module: mod_auth(3)
Context: <Directory>
Related: allow, deny, AuthAccessPassword, AuthName, AuthUserFile, AuthGroupFile, require

`AuthDBType` sets the type of authentication database that is used for the directory.The key difference between the different methods is that dynamic data can be saved when Mnesia and Dets is used.

If Mnesia is used as storage method, Mnesia must be started prio to the webserver. The first time Mnesia is started the schema and the tables must be created before Mnesia is started. A naive example of a module with two functions that creates and start mnesia is provided here. The function shall be sued the first time. `first_start/0` creates the schema and the tables. The second function `start/0` shall be used in consecutive startups. `start/0` Starts Mnesia and wait for the tables to be initiated. This function must only be used when the schema and the tables already is created.

        -module(mnesia_test).
        -export([start/0,load_data/0]).
        -include("mod_auth.hrl").

        first_start()->
             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).

        start()->
            mnesia:start(),
            mnesia:wait_for_tables([httpd_user,httpd_group],60000).

To create the Mnesia tables we use two records defined in mod_auth.hrl so the file must be included.

The first function `first_start/0` creates a schema that specify on which nodes the database shall reside. Then it starts Mnesia and creates the tables. The first argument is the name of the tables, the second argument is a list of options how the table will be created, see Mnesia documentation for more information. Since the current implementation of the mod_auth_mnesia saves one row for each user the type must be bag.

When the schema and the tables is created the second function `start/0`shall be used to start Mensia. It starts Mnesia and wait for the tables to be loaded. Mnesia use the directory specified as `mnesia_dir` at startup if specified, otherwise Mnesia use the current directory.

| For security reasons, make sure that the Mnesia tables are stored outside the document tree of the Web server. If it is placed in the directory which it protects, clients will be able to download the tables.

| Only the `dets` and `mnesia` storage methods allow writing of dynamic user data to disk. `plain` is a read only method.

### DIRECTIVE: "AuthUserFile"

Syntax: `AuthUserFile` filename
Default: - None -
Module: mod_auth(3)
Context: <Directory>
Related: allow, deny, AuthDBType, AuthAccessPassword, AuthGroupFile, AuthName, require

`AuthUserFile` sets the name of a file which contains the list of users and passwords for user authentication. `filename` can be either absolute or relative to the `ServerRoot`.

If using the `plain` storage method, this file is a plain text file, where each line contains a user name followed by a colon, followed by the non-encrypted password. The behavior is undefined if user names are duplicated. For example:

    ragnar:s7Xxv7
    edward:wwjau8

If using the `dets` storage method, the user database is maintained by `dets` and should not be edited by hand. Use the API in this module to create / edit the user database.

This directive is ignored if using the `mnesia` storage method.

| For security reasons, make sure that the `AuthUserFile` is stored outside the document tree of the Web server. If it is placed in the directory which it protects, clients will be able to download it.

### DIRECTIVE: "AuthGroupFile"

Syntax: `AuthGroupFile` filename
Default: - None -
Module: mod_auth(3)
Context: <Directory>
Related: allow, deny, AuthName, AuthUserFile, AuthDBType, AuthAccessPassword, require

`AuthGroupFile` sets the name of a file which contains the list of user groups for user authentication. `filename` can be either absolute or relative to the `ServerRoot`.

If you use the `plain` storage method, the group file is a plain text file, where each line contains a group name followed by a colon, followed by the member user names separated by spaces. For example:

    group1: bob joe ante

If using the `dets` storage method, the group database is maintained by `dets` and should not be edited by hand. Use the API in this module to create / edit the group database.

This directive is ignored if using the `mnesia` storage method.

| For security reasons, make sure that the `AuthGroupFile` is stored outside the document tree of the Web server. If it is placed in the directory which it protects, clients will be able to download it.

### DIRECTIVE: "AuthName"

Syntax: `AuthName` auth-domain
Default: - None -
Module: mod_auth(3)
Context: <Directory>
Related: allow, deny, AuthGroupFile, AuthUserFile, AuthDBType, AuthAccessPassword, require

`AuthName` sets the name of the authorization realm (`auth-domain`) for a directory. This string informs the client about which user name and password to use.

### DIRECTIVE: "AuthAccessPassword"

Syntax: `AuthAccessPassword` password
Default: NoPassword
Module: mod_auth(3)
Context: <Directory>
Related: allow, deny, AuthGroupFile, AuthUserFile, AuthDBType, AuthName, require

If `AuthAccessPassword` is set to other than NoPassword the password is required for all API calls. If the password is set to DummyPassword the password must be changed before any other API calls. To secure the authenticating data the password must be changed after the webserver is started since it otherwise is written in clear text in the configuration file.

### DIRECTIVE: "allow"

Syntax: `allow from` host host ...
Default: `allow from all`
Module: mod_auth(3)
Context: <Directory>
Related: AuthAccessPassword, deny, AuthUserFile, AuthGroupFile, AuthName, AuthDBType require

`allow` defines a set of hosts which should be granted access to a given directory. `host` is one of the following:

`all`
  All hosts are allowed access.
A regular expression (Read `regexp(3)`)
  All hosts having a numerical IP address matching the specific regular expression are allowed access.

For example:

    allow from 123.34.56.11 150.100.23

The host 123.34.56.11 and all machines on the 150.100.23 subnet are allowed access.

### DIRECTIVE: "deny"

Syntax: `deny from` host host ...
Default: `deny from all`
Module: mod_auth(3)
Context: <Directory>
Related: allow, AuthUserFile, AuthGroupFile, AuthName, AuthDBType, AuthAccessPassword, require

`deny` defines a set of hosts which should not be granted access to a given directory. `host` is one of the following:

`all`
  All hosts are denied access.
A regular expression (Read `regexp(3)`)
  All hosts having a numerical IP address matching the specific regular expression are denied access.

For example:

    deny from 123.34.56.11 150.100.23

The host 123.34.56.11 and all machines on the 150.100.23 subnet are denied access.

### DIRECTIVE: "require"

Syntax: `require` entity-name entity entity ...
Default: - None -
Module: mod_auth(3)
Context: <Directory>
Related: allow, deny, AuthUserFile, AuthGroupFile, AuthName, AuthDBType, AuthAccessPassword

`require` defines users which should be granted access to a given directory using a secret password. The allowed syntaxes are:

`require user user-name user-name ...`
  Only the named users can access the directory.
`require group group-name group-name ...`
  Only users in the named groups can access the directory.

### EWSAPI MODULE INTERACTION

Uses the following EWSAPI interaction data, if available:

`{real_name, {Path, AfterPath}}`
  as defined in mod_alias(3).

Exports the following EWSAPI interaction data, if possible:

`{remote_user, User}`
  The user name with which the user has authenticated himself.

Uses the following exported EWSAPI functions:

- mod_alias:path/3

### EXPORTS

`add_user(UserName, Options) -> true| {error, Reason}`
`add_user(UserName, Password, UserData, Port, Dir) -> true | {error, Reason}`
`add_user(UserName, Password, UserData, Address, Port, Dir) -> true | {error, Reason}`

Types:

`UserName = string()`
`Options = [Option]`
`Option = {password,Password} | {userData,UserData} | {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Password = string()`
`UserData = term()`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`AuthPassword =string()`
`Reason = term()`

`add_user/2, add_user/5` and `add_user/6` adds a user to the user database. If the operation is succesful, this function returns `true`. If an error occurs, `{error,Reason}` is returned. When `add_user/2` is called the Password, UserData Port and Dir options is mandatory.

`delete_user(UserName,Options) -> true | {error, Reason}`
`delete_user(UserName, Port, Dir) -> true | {error, Reason}`
`delete_user(UserName, Address, Port, Dir) -> true | {error, Reason}`

Types:

`UserName = string()`
`Options = [Option]`
`Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`AuthPassword = string()`
`Reason = term()`

`delete_user/2, delete_user/3` and `delete_user/4` deletes a user from the user database. If the operation is succesful, this function returns `true`. If an error occurs, `{error,Reason}` is returned. When `delete_user/2` is called the Port and Dir options are mandatory.

`get_user(UserName,Options) -> {ok, #httpd_user} |{error, Reason}`
`get_user(UserName, Port, Dir) -> {ok, #httpd_user} | {error, Reason}`
`get_user(UserName, Address, Port, Dir) -> {ok, #httpd_user} | {error, Reason}`

Types:

`UserName = string()`
`Options = [Option]`
`Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`AuthPassword = string()`
`Reason = term()`

`get_user/2, get_user/3` and `get_user/4` returns a `httpd_user` record containing the userdata for a specific user. If the user cannot be found, `{error, Reason}` is returned. When `get_user/2` is called the Port and Dir options are mandatory.

`list_users(Options) -> {ok, Users} | {error, Reason} <name>list_users(Port, Dir) -> {ok, Users} | {error, Reason}`
`list_users(Address, Port, Dir) -> {ok, Users} | {error, Reason}`

Types:

`Options = [Option]`
`Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`Users = list()`
`AuthPassword = string()`
`Reason = atom()`

`list_users/1, list_users/2` and `list_users/3` returns a list of users in the user database for a specific `Port/Dir`. When `list_users/1` is called the Port and Dir options are mandatory.

`add_group_member(GroupName, UserName, Options) -> true | {error, Reason}`
`add_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}`
`add_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}`

Types:

`GroupName = string()`
`UserName = string()`
`Options = [Option]`
`Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`AuthPassword = string()`
`Reason = term()`

`add_group_member/3, add_group_member/4` and `add_group_member/5` adds a user to a group. If the group does not exist, it is created and the user is added to the group. Upon successful operation, this function returns `true`. When `add_group_members/3` is called the Port and Dir options are mandatory.

`delete_group_member(GroupName, UserName, Options) -> true | {error, Reason}`
`delete_group_member(GroupName, UserName, Port, Dir) -> true | {error, Reason}`
`delete_group_member(GroupName, UserName, Address, Port, Dir) -> true | {error, Reason}`

Types:

`GroupName = string()`
`UserName = string()`
`Options = [Option]`
`Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`AuthPassword = string()`
`Reason = term()`

`delete_group_member/3, delete_group_member/4` and `delete_group_member/5` deletes a user from a group. If the group or the user does not exist, this function returns an error, otherwise it returns `true`. When `delete_group_member/3` is called the Port and Dir options are mandatory.

`list_group_members(GroupName, Options) -> {ok, Users} | {error, Reason}`
`list_group_members(GroupName, Port, Dir) -> {ok, Users} | {error, Reason}`
`list_group_members(GroupName, Address, Port, Dir) -> {ok, Users} | {error, Reason}`

Types:

`GroupName = string()`
`Options = [Option]`
`Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`Users = list()`
`AuthPassword = string()`
`Reason = term()`

`list_group_members/2, list_group_members/3` and `list_group_members/4` lists the members of a specified group. If the group does not exist or there is an error, `{error, Reason}` is returned. When `list_group_members/2` is called the Port and Dir options are mandatory.

`list_groups(Options) -> {ok, Groups} | {error, Reason}`
`list_groups(Port, Dir) -> {ok, Groups} | {error, Reason}`
`list_groups(Address, Port, Dir) -> {ok, Groups} | {error, Reason}`

Types:

`Options = [Option]`
`Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`Groups = list()`
`AuthPassword = string()`
`Reason = term()`

`list_groups/1, list_groups/2` and `list_groups/3` lists all the groups available. If there is an error, `{error, Reason}` is returned. When `list_groups/1` is called the Port and Dir options are mandatory.

`delete_group(GroupName, Options) -> true | {error,Reason} <name>delete_group(GroupName, Port, Dir) -> true | {error, Reason}`
`delete_group(GroupName, Address, Port, Dir) -> true | {error, Reason}`

Types:

`Options = [Option]`
`Option = {port,Port} | {addr,Address} | {dir,Directory} | {authPassword,AuthPassword}`
`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`GroupName = string()`
`AuthPassword = string()`
`Reason = term()`

`delete_group/2, delete_group/3` and `delete_group/4` deletes the group specified and returns `true`. If there is an error, `{error, Reason}` is returned. When `delete_group/2` is called the Port and Dir options are mandatory.

`update_password(Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}`
`update_password(Address,Port, Dir, OldPassword, NewPassword, NewPassword) -> ok | {error, Reason}`

Types:

`Port = integer()`
`Address = {A,B,C,D} | string() | undefined`
`Dir = string()`
`GroupName = string()`
`OldPassword = string()`
`NewPassword = string()`
`Reason = term()`

`update_password/5` and `update_password/6` Updates the AuthAccessPassword for the specified directory. If NewPassword is equal to "NoPassword" no password is requires to change authorisation data. If NewPassword is equal to "DummyPassword" no changes can be done without changing the password first.

### SEE ALSO

httpd(3), mod_alias(3),

### AUTHORS

Mattias Nilsson - support@erlang.ericsson.se
Original implementation: Joakim Grebenö - support@erlang.ericsson.se

inets 4.2
Copyright © 1991-2005 Ericsson AB