<!-- Auth_db Module User's Guide -->

<chapter>

	<title>&adminguide;</title>

	<section id="overview" xreflabel="Overview">
	<title>Overview</title>
	<para>
		This module contains all authentication related functions that need
		the access to the database. This module should be used together with
		auth module, it cannot be used independently because it depends on
		the module. Select this module if you want to use database to store
		authentication information like subscriber usernames and passwords. If
		you want to use radius authentication, then use auth_radius instead.
	</para>

	<section id="rfc-8760-support" xreflabel="RFC 8760 Support">
	        <title>RFC 8760 Support (Strenghtened Authentication)</title>
	        <para>
			Starting with OpenSIPS 3.2, the <ulink url='auth'>auth</ulink>,
			<ulink url='auth_db'>auth_db</ulink> and
			<ulink url='uac_auth'>uac_auth</ulink>
			modules include support for two new digest authentication algorithms
			("SHA-256" and "SHA-512-256"), according to the
	        <ulink url="https://datatracker.ietf.org/doc/html/rfc8760">RFC 8760</ulink>
	        specs.
	        </para>
	</section>
	</section>

	<section id="dependencies" xreflabel="Dependencies">
		<title>Dependencies</title>
		<section>
			<title>&osips; Modules</title>
			<para>
			The module depends on the following modules (in the other words
			the listed modules must be loaded before this module):
			<itemizedlist>
			<listitem>
				<para><emphasis>auth</emphasis> -- Generic authentication
				functions
				</para>
			</listitem>
			<listitem>
				<para><emphasis>database</emphasis> -- Any database module
				(currently mysql, postgres, dbtext)
				</para>
			</listitem>
			</itemizedlist>
		</para>
		</section>
		<section>
			<title>External Libraries or Applications</title>
			<para>
			The following libraries or applications must be installed
			before running &osips; with this module loaded:
			</para>
			<itemizedlist>
				<listitem>
				<para><emphasis>none</emphasis></para>
				</listitem>
			</itemizedlist>
		</section>
	</section>


	<section id="exported_parameters" xreflabel="Exported Parameters">
	<title>Exported Parameters</title>
	<section id="param_db_url" xreflabel="db_url">
		<title><varname>db_url</varname> (string)</title>
		<para>
		This is URL of the database to be used. Value of the parameter depends
		on the database module used. For example for mysql and postgres modules
		this is something like mysql://username:password@host:port/database.
		For dbtext module (which stores data in plaintext files) it is
		directory in which the database resides.
		</para>
		<para>
		<emphasis>
			Default value is <quote>&defaultrodb;</quote>.
		</emphasis>
		</para>
		<example>
		<title><varname>db_url</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "db_url", "&exampledb;")
</programlisting>
		</example>
	</section>

	<section id="param_calculate_ha1" xreflabel="calculate_ha1">
		<title><varname>calculate_ha1</varname> (integer)</title>
		<para>
		This parameter tells the server whether it should considered the
		loaded password (for authentification) as plaintext passwords or
		a pre-calculated HA1 string.
		</para>
		<para>
		Possible meanings of this parameter are:
		</para>
		<itemizedlist>
			<listitem><para><emphasis>1 (calculate HA1)</emphasis> - the loaded
			password is a plaintext password, so OpenSIPS will internally
			calculate the HA1. As the passwords will be loaded from the column
			specified in the <xref linkend="param_password_column"/> parameter,
			be sure this parameter points to a column holding a plaintext password
			(by default, this parameter points to the <quote>ha1</quote> column);
			</para></listitem>

			<listitem><para><emphasis>0 (do <emphasis role='bold'>not</emphasis>
			calculate HA1)</emphasis> - the loaded password is a pre-computed
			HA1 hash (no calculation needed).  The module will load all hashes
			stored in the <xref linkend="param_password_column"/>,
			<xref linkend="param_hash_column_sha256"/> and
			<xref linkend="param_hash_column_sha512t256"/> columns, then use
			the hash corresponding to the hashing algorithm selected for a
			given digest authentication challenge.
			</para>

			<para>
			The content of the hash columns can be generated as follows:
			<itemizedlist>
			<listitem><para>password_column: MD5(username:realm:password)
			</para></listitem>
			<listitem><para>hash_column_sha256: SHA-256(username:realm:password)
			</para></listitem>
			<listitem><para>hash_column_sha512t256: SHA-512-256(username:realm:password)
			</para></listitem>
			</itemizedlist>
			</para>

			</listitem>
		</itemizedlist>
		<para>
			Default value of this parameter is
			<emphasis>0 (use hashed passwords)</emphasis>.
		</para>
		<example>
		<title><varname>calculate_ha1</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "calculate_ha1", 1)
</programlisting>
		</example>
	</section>

	<section id="param_use_domain" xreflabel="use_domain">
		<title><varname>use_domain</varname> (integer)</title>
		<para>
		If true (not 0), domain will be also used when looking up in the
		subscriber table. If you have a multi-domain setup, it is strongly
		recommended to turn on this parameter to avoid username overlapping
		between domains.
		</para>
		<para>
		IMPORTANT: before turning on this parameter, be sure that the
		<varname>domain</varname> column in <varname>subscriber</varname>
		table is properly populated.
		</para>
		<para>
		Default value is <quote>0 (false)</quote>.
		</para>
		<example>
		<title><varname>use_domain</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "use_domain", 1)
		</programlisting>
		</example>
	</section>

	<section id="param_load_credentials" xreflabel="load_credentials">
		<title><varname>load_credentials</varname> (string)</title>
		<para>
		This parameter specifies credentials to be fetched from database when
		the authentication is performed. The loaded credentials will be stored
		in AVPs. If the AVP name is not specificaly given, it will be used a
		NAME AVP with the same name as the column name.
		</para>
		<para>
		 Parameter syntax:
		<itemizedlist>
			<listitem><para><emphasis>
			load_credentials = credential (';' credential)*
			</emphasis></para></listitem>
			<listitem><para><emphasis>
			credential = (avp_specification '=' column_name) |
							(column_name)
			</emphasis></para></listitem>
			<listitem><para><emphasis>
			avp_specification = '$avp(' + NAME + ')'
			</emphasis></para></listitem>
		</itemizedlist>
		</para>
		<para>
		Default value of this parameter is <quote>rpid</quote>.
		</para>
		<example>
		<title><varname>load_credentials</varname> parameter usage</title>
		<programlisting format="linespecific">
# load rpid column into $avp(13) and email_address column
# into $avp(email_address)
modparam("auth_db", "load_credentials", "$avp(13)=rpid;email_address")
</programlisting>
		</example>
	</section>

	<section id="param_skip_version_check" xreflabel="skip_version_check">
		<title><varname>skip_version_check</varname> (int)</title>
		<para>
		This parameter specifies not to check the auth table version. This
		parameter should be set when a custom authentication table is used.
		</para>
		<para>
		Default value is <quote>0 (false)</quote>.
		</para>
		<example>
		<title><varname>skip_version_check</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "skip_version_check", 1)
		</programlisting>
		</example>
	</section>

	<section id="param_user_column" xreflabel="user_column">
		<title><varname>user_column</varname> (string)</title>
		<para>
		This is the name of the column in a 'SUBSCRIBER' like table holding
		the usernames. Default value is fine for most people.
		Use the parameter if you really need to change it.
		</para>
		<para>
		Default value is <quote>username</quote>.
		</para>
		<example>
		<title><varname>user_column</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "user_column", "user")
</programlisting>
		</example>
	</section>

	<section id="param_domain_column" xreflabel="domain_column">
		<title><varname>domain_column</varname> (string)</title>
		<para>
		This is the name of the column in a 'SUBSCRIBER' like table holding
		the domains of users. Default value is fine for most people.
		Use the parameter if you really need to
		change it.
		</para>
		<para>
		Default value is <quote>domain</quote>.
		</para>
		<example>
		<title><varname>domain_column</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "domain_column", "domain")
</programlisting>
		</example>
	</section>

	<section id="param_password_column" xreflabel="password_column">
		<title><varname>password_column</varname> (string)</title>
		<para>
		This is the name of the column in a <emphasis>"subscriber"</emphasis>
		like table holding MD5 HA1 hash strings or plaintext passwords.  An MD5 HA1
		hash is an MD5 hash of username, password and realm.  Storing hashes in the
		DB (as opposed to passwords directly) is much more secure, because the
		server does not need to know plaintext passwords and because it is
		computationally infeasible for an attacker to reverse-obtain a password
		from an HA1 string.
		</para>
		<para>
		Default value is <quote>ha1</quote>.
		</para>
		<example>
		<title><varname>password_column</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "password_column", "password")
</programlisting>
		</example>
	</section>

	<section id="param_hash_column_sha256" xreflabel="hash_column_sha256">
		<title><varname>hash_column_sha256</varname> (string)</title>
		<para>
		The name of the column holding SHA-256 HA1 hashes
		(<ulink url="https://datatracker.ietf.org/doc/html/rfc8760">RFC 8760</ulink> support).

		</para>
		<para>
		Default value is <quote>ha1_sha256</quote>.
		</para>
		<example>
		<title><varname>password_column</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "hash_column_sha256", "ha1_sha256")
</programlisting>
		</example>
	</section>

	<section id="param_hash_column_sha512t256" xreflabel="hash_column_sha512t256">
		<title><varname>hash_column_sha512t256</varname> (string)</title>
		<para>
		The name of the column holding SHA-512/256 HA1 hashes.
		(<ulink url="https://datatracker.ietf.org/doc/html/rfc8760">RFC 8760</ulink> support).
		</para>
		<para>
		Default value is <quote>ha1_sha512t256</quote>.
		</para>
		<example>
		<title><varname>password_column</varname> parameter usage</title>
		<programlisting format="linespecific">
modparam("auth_db", "hash_column_sha512t256", "ha1_sha512t256")
</programlisting>
		</example>
	</section>

	<section id="param_uri_user_column" xreflabel="uri_user_column">
		<title><varname>uri_user_column</varname> (string)</title>
		<para>
		Column holding usernames in an 'URI' like table.
		</para>
		<para>
		<emphasis>
			Default value is <quote>username</quote>.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>uri_user_column</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("auth_db", "uri_user_column", "username")
...
</programlisting>
		</example>
	</section>

	<section id="param_uri_domain_column" xreflabel="uri_domain_column">
		<title><varname>uri_domain_column</varname> (string)</title>
		<para>
		Column holding domain in an 'URI' like table.
		</para>
		<para>
		<emphasis>
			Default value is <quote>domain</quote>.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>uri_domain_column</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("auth_db", "uri_domain_column", "domain")
...
</programlisting>
		</example>
	</section>

	<section id="param_uri_uriuser_column" xreflabel="uri_uriuser_column">
		<title><varname>uri_uriuser_column</varname> (string)</title>
		<para>
		Column holding &uri; username in an 'URI' like table.
		</para>
		<para>
		<emphasis>
			Default value is <quote>uri_user</quote>.
		</emphasis>
		</para>
		<example>
		<title>Set <varname>uriuser_column</varname> parameter</title>
		<programlisting format="linespecific">
...
modparam("auth_db", "uri_uriuser_column", "uri_user")
...
</programlisting>
		</example>
	</section>



	</section>

	<section id="exported_functions" xreflabel="exported_functions">
	<title>Exported Functions</title>
	<section id="func_www_authorize" xreflabel="www_authorize()">
		<title>
			<function moreinfo="none">www_authorize(realm, table)</function>
		</title>
		<para>
		The function verifies the received credentials against a
		"SUBSCRIBER"-like table according to digest authentication as per
		<ulink url="http://www.ietf.org/rfc/rfc2617.txt">RFC2617</ulink>.
		If the credentials are verified successfully then the function will
		succeed and mark the credentials as authorized (marked credentials
		can be later used by some other functions). If the function was
		unable to verify the
		credentials for some reason then it will fail and the script should
		call <function moreinfo="none">www_challenge</function> which will
		challenge the user again.
		</para>
		<para>Negative codes may be interpreted as follows:</para>
		<itemizedlist>
			<listitem><para>
			<emphasis>-5 (generic error)</emphasis> - some generic error
			occurred and no reply was sent out;
			</para></listitem>
			<listitem><para>
			<emphasis>-4 (no credentials)</emphasis> - credentials were not
			found in request;
			</para></listitem>
			<listitem><para>
			<emphasis>-3 (stale nonce)</emphasis> - stale nonce;
			</para></listitem>
			<listitem><para>
			<emphasis>-2 (invalid password)</emphasis> - valid user, but
			wrong password;
			</para></listitem>
			<listitem><para>
			<emphasis>-1 (invalid user)</emphasis> - authentication user does
			not exist.
			</para></listitem>
		</itemizedlist>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para><emphasis>realm (string)</emphasis> - Realm is an opaque string that
			the user agent should present to the user so it can decide what
			username and password to use. Usually this is domain of the host
			the server is running on.
			</para>
			<para>
			If an empty string <quote></quote> is used then the server will
			generate it from the request. In case of REGISTER requests To
			header field domain will be used (because this header field
			represents a user being registered), for all other messages From
			header field domain will be used.
			</para>
			<para>
			The string may contain pseudo variables.
			</para>
		</listitem>
		<listitem>
			<para><emphasis>table (string)</emphasis> - Table to be used to lookup
			usernames and passwords (usually subscribers table).
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title><function moreinfo="none">www_authorize</function> usage</title>
		<programlisting format="linespecific">
...
if (!www_authorize("siphub.net", "subscriber"))
	www_challenge("siphub.net", "auth");
...
</programlisting>
		</example>
	</section>

	<section id="func_proxy_authorize" xreflabel="proxy_authorize()">
		<title>
			<function moreinfo="none">proxy_authorize(realm, table)</function>
		</title>
		<para>
		The function verifies the received credentials against a
		"SUBSCRIBER"-like table according to digest authentication as per
		<ulink url="http://www.ietf.org/rfc/rfc2617.txt">RFC2617</ulink>. If
		the credentials are verified successfully then the function will
		succeed and mark the credentials as authorized (marked credentials can
		be later used by some other functions). If the function was unable to
		verify the credentials for some reason then it will fail and
		the script should call
		<function moreinfo="none">proxy_challenge</function> which will
		challenge the user again.
		</para>
		<para>Negative codes may be interpreted as follows:</para>
		<itemizedlist>
			<listitem><para>
					<emphasis>-5 (generic error)</emphasis> - some generic
					error occurred and no reply was sent out;
				</para></listitem>
			<listitem><para>
					<emphasis>-4 (no credentials)</emphasis> - credentials
					were not found in request;
				</para></listitem>
			<listitem><para>
					<emphasis>-3 (stale nonce)</emphasis> - stale nonce;
				</para></listitem>
			<listitem><para>
					<emphasis>-2 (invalid password)</emphasis> - valid user,
					but wrong password;
				</para></listitem>
			<listitem><para>
					<emphasis>-1 (invalid user)</emphasis> - authentication
					user does not exist.
				</para></listitem>
		</itemizedlist>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para><emphasis>realm (string)</emphasis> - Realm is an opaque string that
			the user agent should present to the user so it can decide what
			username and password to use. Usually this is domain of the host
			the server is running on.
			</para>
			<para>
			If an empty string <quote></quote> is used then the server will
			generate it from the request. From header field domain will be
			used as realm.
			</para>
			<para>
			The string may contain pseudo variables.
			</para>
		</listitem>
		<listitem>
			<para><emphasis>table (string)</emphasis> - Table to be used to lookup
			usernames and passwords (usually subscribers table).
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title>proxy_authorize usage</title>
		<programlisting format="linespecific">
...
if (!proxy_authorize("", "subscriber"))
	proxy_challenge("", "auth");  # Realm will be autogenerated
...
</programlisting>
		</example>
	</section>

	<section id="func_db_is_to_authorized" xreflabel="db_is_to_authorized()">
		<title>
		<function moreinfo="none">db_is_to_authorized(table)</function>
		</title>
		<para>
		The function checks against a  'URI' like table to see if the
		username extracted from the To header URI is allowed/authorized to
		use the credentials (authentication username) validated by
		<xref linkend="func_www_authorize"/>.
		</para>
		<para>
		The function is part of the mechanism that allows to create
		mapping between the SIP users (from the FROM/TO headers) and the
		authentication users (from a SUBSCRIBER-like table) that they use. The
		mapping is stored into an URI-like table.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para><emphasis>table (string)</emphasis> - Table to be used to lookup
			for the URI/AUTH mappings (usually the URI table).
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title><function>db_is_to_authorized</function> usage</title>
		<programlisting format="linespecific">
...
if (!db_is_to_authorized("uri")) {
	xlog("User $tu is not authorized to authenticate with $au credential\n");
}
...
</programlisting>
		</example>
	</section>

	<section id="func_db_is_from_authorized" xreflabel="db_is_from_authorized()">
		<title>
		<function moreinfo="none">db_is_from_authorized(table)</function>
		</title>
		<para>
		Similar to <xref linkend="func_db_is_to_authorized"/> but instead of
		checking the TO header URI, the FROM header URI is checked.
		</para>
	</section>

	<section id="func_db_does_uri_exist" xreflabel="db_does_uri_exist()">
		<title>
		<function moreinfo="none">db_does_uri_exist(uri, table)</function>
		</title>
		<para>
		Checks if the username@domain from the given &uri; is an existing
		user in a 'SUBSCRIBER' like table.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para><emphasis>uri (string)</emphasis> - The SIP URI to be tested. It must
			hold a username part for a valid check. Variables are allowed.
			</para>
		</listitem>
		<listitem>
			<para><emphasis>table (string)</emphasis> - Table to be used to search
			for the URI (usually the SUBSCRIBER table).
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title><function>db_does_uri_exist</function> usage</title>
		<programlisting format="linespecific">
...
if (db_does_uri_exist($ru, "subscriber")) {
	...
}
...
</programlisting>
		</example>
	</section>

	<section id="func_db_get_auth_id" xreflabel="db_get_auth_id()">
		<title>
		<function moreinfo="none">db_get_auth_id(table, uri, auth, realm)</function>
		</title>
		<para>
		Checks given uri-string username against an 'URI' like table.
		Returns true if the user exists in the database, and sets the given
		variables to the authentication id and realm corresponding to
		the given uri.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para><emphasis>table (string)</emphasis> - Table to be used to search
			for the URI (usually the URI table).
			</para>
		</listitem>
		<listitem>
			<para><emphasis>uri (string)</emphasis> - The input SIP URI to be tested.
			It must hold a username part for a valid check.
			Variables are allowed.
			</para>
		</listitem>
		<listitem>
			<para><emphasis>auth (var)</emphasis> - an output variable to store the
			found authentication id matching the given SIP URI.
			</para>
		</listitem>
		<listitem>
			<para><emphasis>realm (var)</emphasis> - an output variable to store the
			found authentication realm matching the given SIP URI.
			</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE ,FAILURE_ROUTE and
		LOCAL_ROUTE.
		</para>
		<example>
		<title><function>db_get_auth_id</function> usage</title>
		<programlisting format="linespecific">
...
if (db_get_auth_id("uri", $ru, $avp(auth_id), $avp(auth_realm))) {
	...
}
...
</programlisting>
		</example>
	</section>

	</section>
</chapter>

