An authorization scenario is a small configuration language to describe who can perform an operation and which authentication method is requested for it. An authorization scenario is an ordered set of rules. The goal is to provide a simple and flexible way to configure authorization and required authentication method for each operation.
The function to evaluate scenario is described in section internals.
List parameters controlling the behavior of commands are linked to different authorization scenarios. For example: the send private parameter is related to the send.private scenario.
There are four possible locations for an authorization scenario. When Sympa seeks to apply an authorization scenario:
/home/sympa/list_data/<list>/scenari or /home/sympa/my.domain.org/list_data/<list>/scenari if you use virtual hosts/home/sympa/etc/my.domain.org/scenari,/home/sympa/etc/scenari,/home/sympa/default/scenari, which is the directory installed by the Makefile.When customizing scenario for your own site, robot or list, don't modify .../sympa/bin/scenari content or the next Sympa update will overwrite it (you must never modify anything in .../sympa/bin/ unless you are patching Sympa). You can modify Sympa behavior if you are creating a new scenario with the same name as one of the scenario already included in the distribution but with a location related to the target site, robot or list. You can also add a new scenario ; it will automatically add an accepted value for the related parameter.
Basically, a scenario file is composed of a title on the first line and a set of rules on the following lines.
The first line of a scenario file can contain its title. This is the text that will later appear in the drop-down menu of your administration web interface. This title can be just plain text:
Restricted to subscribers
It can also be set to be internationalized:
title.gettext Restricted to subscribers
That way, the character string following title.gettext can be handled by Sympa internationalization process.
Each authorization scenario rule contains:
sender for the sender's email, list for the list name, etc.smtp, md5 or smime. The rule is applied by Sympa if both the condition and authentication method match the runtime context.smtp is used if Sympa uses the SMTP From: header ,md5 is used if a unique MD5 key as been returned by the requestor to validate the message,smime is used for signed messages (see configuration to recognize S/MIME signatures);Example:
del.auth
title.us deletion performed only by list owners, need authentication
title.fr suppression r\'eserv\'ee au propri\'etaire avec authentification
title.es eliminacin reservada slo para el propietario, necesita autentificacin
is_owner([listname],[sender]) smtp -> request_auth
is_listmaster([sender]) smtp -> request_auth
true() md5,smime -> do_it
An authorization scenario consists of rules, evaluated in order beginning with the first.
custom_vars allows you to introduce custom parameters in your scenario.
verify_netmask allows the user to configure their local network to only be accessible to those that are members of it. For more information refer to intranet restrictions
perl_regexp can contain the string [host] (interpreted at run time as the list or robot domain). The variable notation [msg_header-><smtp_key_word>] is interpreted as the SMTP header value only when evaluating the authorization scenario for sending messages. It can be used, for example, to require editor validation for multipart messages. [msg_part->type] and [msg_part->body] are the MIME part content-types and bodies; the body is available for MIME parts in text/xxx format only.
Refer to Tasks for date format definition
A bunch of authorization scenarios are provided with the Sympa distribution; they provide a large set of configuration that allows the creation of lists for most purposes. But you will probably create authorization scenarios for your own needs. In this case, do not forget to restart Sympa and WWSympa, because authorization scenarios are not reloaded dynamically.
These standard authorization scenarios are located in the /home/sympa/bin/etc/scenari/ directory. Default scenarios are named <command>.default.
You may also define and name your own authorization scenarios. Store them in the /home/sympa/etc/scenari directory. They will not be overwritten by newer Sympa releases. Scenarios can also be defined for a particular virtual host (using directory /home/sympa/etc/<robot>/scenari) or for a list (/home/sympa/list_data/<robot>/<list>/scenari ). Sympa will not dynamically detect that a list configuration should be reloaded after a scenario has been changed on disk.
Example: copy the previous scenario to scenari/subscribe.rennes1:
equal([sender], 'userxxx@univ-rennes1.fr') smtp,smime -> reject match([sender], /univ-rennes1\.fr$/) smtp,smime -> do_it true() smtp,smime -> owner
You may now refer to this authorization scenario in any list configuration file, for example:
subscribe rennes1
Yous can specify three different authentication methods to base your rules on: smtp, smime and md5.
these methods take a different meaning if you consider them in a web or mail context.
Indeed if you consider, for example, the scenario send: it will be evaluated when people try to send a message to a list.
But the same scenario file will be used in both cases. That means that the same authentication method will be used, whichever context we're in. It is consequently important to understand what interpretation to give to each authentication method according to the context.
Here is a description of what is evaluated to authenticate the user depending of the context: web or mail.
| Method | Mail context | Web context |
|---|---|---|
smtp | the “From:” field of the message | Nothing - unused in web context |
smime | the S/MIME X509 signature of the email | An X509 certificate installed in the user's browser |
md5 | the MD5 hash in the subject of the message | the authentication informations provided to Sympa (login/password) |
dkim | the DKIM signature of the message | Nothing - unused in web context |
Note that md5 will be used, in a mail context, when users answer to an authentication request, or when editors moderate a message by replying to a moderation request mail.
In most cases, smtp or dkim will be used for mails, and md5 for the web.
The difference between editor and editorkey is that, with editor, the message is simply forwarded to moderators, who can then forward it to the list if they like. editorkey assigns a key to the message and sends it to moderators together with the message. So moderators can just send back the key to distribute the message. Please note that moderation from the web interface is only possible when using editorkey, because otherwise there is no copy of the message saved on the server.
The quiet can be part of the scenario action result. When using this option, no notification is sent to the message sender. For example, if a scenario rule is applied and result in editorkey,quiet the sender of the message will not receive the automatic information message telling him that his message has been forwarded to the list editor. This is an important issue to prevent backscatter messages. backscatter messages are messages you receive as an automatic answer to a message you never sent. The following web page give you more details :
Sympa version 6.0 and later of Sympa provide a better mechanism to prevent backscatter. See https://www.sympa.org/dev-manual/antispam
Rules are defined as follows:
<rule> ::= <condition> <auth_list> -> <action>
<condition> ::= [!] <condition
| true ()
| equal (<var>, <var>)
| less_than (<var>, <var>)
| match (<var>, /perl_regexp/)
| search (<named_filter_file>)
| is_subscriber (<listname>, <var>)
| is_owner (<listname>, <var>)
| is_editor (<listname>, <var>)
| is_listmaster (<var>)
| older (<date>, <date>) # true if first date is anterior to the second date
| newer (<date>, <date>) # true if first date is posterior to the second date
| CustomCondition::<package_name> (<var>*)
<var> ::= [email] | [sender] | [user-><user_key_word>] | [previous_email]
| [env->remote_host] | [env->remote_addr] | [user_attributes-><user_attributes_keyword>]
| [subscriber-><subscriber_key_word>] | [list-><list_key_word>] | [env-><env_var>]
| [conf-><conf_key_word>] | [msg_header-><smtp_key_word>] | [msg_body]
| [msg_part->type] | [msg_part->body] | [msg_encrypted] | [is_bcc] | [current_date]
| [topic-auto] | [topic-sender,] | [topic-editor] | [topic] | [topic-needed]
| [custom_vars-><custom_var_name>] | <string>
[is_bcc] ::= set to 1 if the list is neither in To: nor Cc:
[sender] ::= email address of the current user (used on web or mail interface). Default value is 'nobody'
[previous_email] ::= old email when changing subscription email in preference page.
[msg_encrypted] ::= set to 'smime' if the message was S/MIME encrypted
[topic-auto] ::= topic of the message if it has been automatically tagged
[topic-sender] ::= topic of the message if it has been tagged by sender
[topic-editor] ::= topic of the message if it has been tagged by editor
[topic] ::= topic of the message (this variable has a value if any of the previous [topic-*] variable has a value.
[topic-needed] ::= the message has not got any topic and message topic are required for the list
/perl_regexp/ ::= a perl regular expression. Don't forget to escape special characters (^, $, \{, \(, ...)
Check http://perldoc.perl.org/perlre.html for regular expression syntax.
<date> ::= '<date_element> [ +|- <date_element>]'
<date_element> ::= <epoch_date> | <var> | <date_expr>
<epoch_date> ::= <integer>
<date_expr> ::= <integer>y<integer>m<integer>d<integer>h<integer>min<integer>sec
<custom_var_name> ::= name of the custom parameter you want to use.
<listname> ::= [listname] | '<listname_string>' | '<listname_string>@>domain_string>'
<auth_list> ::= <auth>,<auth_list> | <auth>
<auth> ::= smtp|md5|smime
<action> ::= do_it [,notify]
| do_it [,quiet]
| reject(reason=<reason_key>) [,quiet]
| reject(tt2=<tpl_name>) [,quiet]
| request_auth
| owner
| editor
| editorkey[,quiet]
| listmaster
<reason_key> ::= match a key in mail_tt2/authorization_reject.tt2 template corresponding to
an information message about the reason of the reject of the user
notify ::= sends a notification to list owner
<tpl_name> ::= corresponding template (<tpl_name>.tt2) is send to the sender
<user_key_word> ::= email | gecos | lang | password | cookie_delay_user
| <additional_user_fields>
<user_attributes_key_word> ::= one of the user attributes provided by the SSO system via environment variables. The [user_attributes] structure is available only if user authenticated with a generic_sso.
<subscriber_key_word> ::= email | gecos | bounce | reception
| visibility | date | update_date
| <additional_subscriber_fields>
<list_key_word> ::= name | host | address | lang | max_size | priority | reply_to |
status | subject | account | total
<conf_key_word> ::= domain | email | listmaster | default_list_priority |
sympa_priority | request_priority | lang | max_size
<named_filter_file> ::= filename ending with .ldap , .sql or .txt.
<package_name> ::= name of a perl package in /etc/custom_conditions/ (small letters)
At the moment, Named Filters are only used in authorization scenarios. They enable to select a category of people who will be authorized or not to realize some actions.
As a consequence, you can grant privileges in a list to people belonging to an LDAP directory, an SQL database or a flat text file, thanks to an authorization scenario.
Note that only a subset of variables available in the scenario context are available here (including [sender] and [listname]).
People are selected through an LDAP filter defined in a configuration file. This file must have the extension '.ldap'. It is stored in /home/sympa/etc/search_filters/.
You must give a few information in order to create a LDAP Named Filter:
host suffix filter (mail_attribute = [sender]), as shown in the example. You will have to replace mail_attribute by the name of the attribute for the email. Sympa checks whether the user belongs to the category of people defined in the filter.scope base: search only the base object.one: search the entries immediately below the base object.sub: search the whole tree below the base object. This is the default option.bind_dn bind_password bind_dn above.
example.ldap: we want to select the teachers of mathematics in the University of Rennes 1 in France:
host ldap.univ-rennes1.fr:389,ldap2.univ-rennes1.fr:390
suffix dc=univ-rennes1.fr,dc=fr
filter (&(canonic_mail = [sender])(EmployeeType = prof)(subject = math))
scope sub
People are selected through an SQL filter defined in a configuration file. This file must have the extension '.sql'. It is stored in /home/sympa/etc/search_filters/.
To create an SQL Named Filter, you have to configure SQL host, database and options, the same way you did it for the main Sympa database in sympa.conf. Of course, you can use different database and options. Sympa will open a new Database connection to execute your statement.
Please refer to section Database related for a detailed explanation of each parameter.
Here, all database parameters have to be grouped in one sql_named_filter_query paragraph.
db_type db_type mysql|SQLite|Pg|Oracle|Sybase; Database management system used. Mandatory and case sensitive.db_host db_name statement SELECT COUNT(*)... statement is the perfect query for this parameter. The keyword in the SQL query will be replaced by the sender's email.sympa.conf section for description.db_userdb_passworddb_optionsdb_envdb_portdb_timeout
example.sql: we want to select the teachers of mathematics in the University of Rennes 1 in France:
sql_named_filter_query
db_type mysql
db_name people
db_host dbserver.rennes1.fr
db_user sympa
db_passwd pw_sympa_mysqluser
statement SELECT count(*) as c FROM users WHERE mail=[sender] AND EmployeeType='PROFESSOR' AND department='mathematics'
The search condition is used in authorization scenarios.
The syntax of this rule is:
search(example.ldap) smtp,smime,md5 -> do_it
search(blacklist.txt) smtp,smime,md5 -> do_it
The variable used by search is the name of the LDAP configuration file or a txt matching enumeration.
Note that Sympa processes maintain a cache of processed search conditions to limit access to the LDAP directory or SQL server; each entry has a lifetime of one hour in the cache.
When using the '.txt' file extension, each line is used to try to match the sender email address. You can use the “*” character as a joker to replace any string.
Here is an example of such a file:
david.verdin@cru.fr *salaun*
With such a file, the rule would be true for the following email addresses:
It would be false for the following email addresses :
This feature is used by the blacklist implicit scenario rule (see Blacklist).
The method of authentication does not change.
Scenarios can also contain includes:
include commonreject
match([sender], /cru\.fr$/) smtp,smime -> do_it
true() smtp,smime -> owner
In this case, Sympa applies recursively the scenario named include.commonreject before introducing the other rules. This possibility was introduced in order to facilitate the administration of common rules.
You can define a set of common scenario rules, used by all lists. include.<action>.header is automatically added to evaluated scenarios. Note that you will need to restart Sympa processes to force reloading of list config files.
For each service listed in parameter use_blacklist (see use_blacklist), the following implicit scenario rule is added at the beginning of the scenario:
search(blacklist.txt) smtp,md5,pgp,smime -> reject,quiet
The goal is to block messages or other service requests from unwanted users. The blacklist can be defined for the robot or for the list. At the list level, the blacklist is to be managed by list owner or list editor via the web interface.
You can use a Perl package of your own to evaluate a custom condition. It can be useful if you have very complex tasks to carry out to evaluate your condition (web services queries...). In this case, you should write a Perl module, place it in the CustomCondition namespace, with one verify fonction that has to return 1 to grant access, undef to warn of an error, or anything else to refuse the authorization.
This Perl module:
custom_conditions of the etc directory of your Sympa installation, or of a robot;CustomCondition namespace;verify static fonction;
For example, lets write the smallest custom condition that always returns 1.
/home/sympa/etc/custom_conditions/yes.pm :
#!/usr/bin/perl package CustomCondition::yes; use strict; use Log; # optional : we log parameters sub verify { my @args = @_; foreach my $arg (@args) { do_log ('debug3', 'arg: ', $arg); } # I always say 'yes' return 1; } ## Packages must return true. 1;
We can use this custom condition that way:
CustomCondition::yes(,,) smtp,smime,md5 -> do_it true() smtp,smime -> reject
Note that the ,, are optional, but it is the way you can pass information to your package. Our yes.pm will print the values in the logs.
Remember that the package name has to be lowercase, but the CustomCondition namespace is case sensitive. If your package returns undef, the sender will receive an 'internal error' mail. If it returns anything else but 1, the sender will receive a 'forbidden' error.
this tuto was also submitted by Thomas Berry, JPL, NASA. Thanks to him!
Scenario condition, message vars include:
[msg_body] [msg_part->body]
When creating scenario rules that evaluate message content, two rules must be created when passing the contents of a message to a condition: one rule for plain text messages (msg_body) and a second rule for multi-part MIME messages (msg_part).
For example, I wrote a CustomCondition module that parses the URLs in a message and compares them with a list of approved URLs:
(send.url_eval)
title.us Moderated with URL verification CustomCondition::urlreview([listname],[sender],[msg_body]) smtp,smime,md5 -> reject() CustomCondition::urlreview([listname],[sender],[msg_part->body]) smtp,smime,md5 -> reject() true() smtp,smime,md5 -> editorkey
The CustomCondition module returns undef if the message contents are not provided by the rule. If the message contents are multi-part MIME, then the [msg_body] passed by the first rule is undefined, and the CustomCondition module returns undef causing the scenario to move on to the next rule which passes the parts of the multi-part MIME message to the module.
As for the CustomCondition module, it was written to evaluate both plain text (SCALAR) and multi-part MIME (ARRAY reference) being passed to the condition:
(urlreview.pm)
package CustomCondition::urlreview; ... sub verify { my $listname = shift or return; my $sender = shift or return; my $body; foreach my $part (@_) { $body .= ref $part eq "ARRAY" ? join " ", @{$part} : $part; } return unless defined $body; ... } ... 1;
Because Sympa is distributed with many default scenario files, you may want to hide some of them to list owners (to make list administration menus shorter and readable). To hide a scenario file, you should create an empty file with the :ignore suffix. Depending on where this file has been created, it will make it be ignored at either a global, robot or list level.
Example:
/home/sympa/etc/my.domain.org/scenari/send.intranetorprivate:ignore
The intranetorprivate send scenario will be hidden (on the web admin interface), at the my.domain.org robot level only.