Introduction

PicoAuth is a plugin for Pico CMS 2.0 providing various means of authentication and authorization to pages. The plugin requires PHP >= 5.6.0.

The functionality of the plugin is contained in independent modules that can be individually enabled to suit the needs of the website owner. Simple description of the modules that are included in the plugin:

  • Local user accounts

    • Visitors can login to the site using accounts stored locally
    • User accounts defined in a configuration file
    • User registration (optional)
    • Password reset function (optional)
    • Users can change their password (optional)
  • Login using OAuth 2.0 services

    • Visitors can login to the site using a 3rd party service that supports the OAuth 2.0 protocol
  • Access control

    • Access control to Pico pages based on permissions of an authenticated user
  • Page locks

    • Can be used to display selected pages only after the correct page key phrase is entered (no authentication required)

Installation

1) Plugin installation

Installation using composer

If your Pico CMS has been installed using composer (using composer create-project picocms/pico-composer), PicoAuth plugin can be easily installed by running the following command in the root of your Pico installation.

composer require picoauth/picoauth

Installation without composer

Installing PicoAuth plugin without composer is not recommended as it makes it difficult to receive updates. It can be used for example to try out the plugin if composer is not available. Such an installation can be done by extracting the plugin archive to the plugins/ directory of your Pico CMS installation so the files of the plugin will be located under plugins/PicoAuth/.

2) Plugin configuration

After the plugin is present, navigate to PicoAuth installer on https://www.YourPicoSite.com/?PicoAuth. It will check your server configuration and walk you through a selection of components you want to include. After the plugin is configured, you can start using the selected modules - a guide for each of them is on separate pages:

  • LocalAuth
  • OAuth
  • PageACL
  • PageLock

PicoAuth security

The level security of security depends on a proper configuration. The following points should be considered:

  • Config files and Content files not accessible
    • Default Pico directory structure has content and config directory inside of the web server root and relies on .htaccess configuration for access restriction to these locations. We recommend moving both directories to a location outside of the web root. After they are moved, change content_dir in Pico's config.yml and 2nd argument in Pico constructor in index.php. If you don't have non-webroot locations available, make sure access to these directories and their contents is not allowed and directory listing is disabled.
  • Website over HTTPS only
    • None of PicoAuth modules can provide sufficient security if the traffic is interceptable over a non-encrypted channel.
  • Correct session configuration
  • Enable rate limiting
    • Provides brute-force prevention on login forms and other critical actions. Refer to the Rate limiting page.
  • Enable logging
    • Allows monitoring of interesting events and troubleshooting configuration errors. Refer to the Set up logging page.

Plugin configuration

The generic configuration of the plugin is located in the Pico configuration file config/config.yml under the name of the plugin: PicoAuth.

Configuration options

  • Enabled plugin modules - Key authModules is an array with the names of the modules that should be registered. The configuration bellow enables all available modules:

    PicoAuth:
      authModules: [ LocalAuth, OAuth, PageACL, PageLock ]
  • Rate limiting - Key rateLimit (boolean value) can be used to enable/disable rate limiting in modules that utilize it. Read more in the Rate limiting section. The default value is: rateLimit: true.

  • Debug mode - Key debug (boolean value) can be used to enable/disable debug mode, which will display error details of critical errors in the module execution. This should not be enabled on a page that is publicly accessible, as it can lead to information disclosure about the Pico installation (e.g. full server path).

  • Page array altering - Key alterPageArray (boolean value). If enabled, pages with restricted access will be removed from Pico's page array and won't appear in the menus (if the used template is using Pico's page array to show menu items).

  • Redirection options

      afterLogin: "index"           # Pico page URL to redirect to after successful login
      afterLogout: "index"          # Pico page URL to redirect to after logout
  • Session interval - Key sessionInterval (non-negative integer or false) can be used to configure a regeneration of the session ID on specified intervals. If set to a non-negative integer, the session ID will be regenerated as soon as the specified interval (in seconds) is reached. Can be disabled by setting the value to false. The default value is 900 (15 minutes).

  • Session idle timeout - Key sessionIdle (non-negative integer or false) can be used to invalidate the session after a specified inactivity period. If set to a non-negative integer, the session will be invalidated after the specified idle period (in seconds). Can be disabled by setting the value to false. The default value is 3600 (1 hour).

  • Session absolute timout - Key sessionTimeout (non-negative integer or false) can be used to set the maximum session lifetime. If set to a non-negative integer, the session will be invalidated after its lifetime is greater or equal to specified duration (in seconds) is reached. Can be disabled by setting the value to false. The default value is 7200 (2 hours).

The default configuration

These are the default options, that are applied implicitly without a need of being present in the configuration file.

PicoAuth:
    authModules: [ Installer ]
    rateLimit: true
    debug: false
    alterPageArray: false
    sessionInterval: 900
    sessionIdle: 3600
    sessionTimeout: 7200
    afterLogin: "index"
    afterLogout: "index"

Write permissions

Some components of the PicoAuth plugin require write permissions in order to function properly. All function that require write access are disabled in the default plugin configuration. This page provides a summary of write permissions for the functions that require it.

User accounts - permissions

The following rights are required, if one of the following is enabled: user registration, password reset, password change:

  • Write access to config/PicoAuth/users or write access to config/PicoAuth to create the users directory.
  • Write access to the configuration file config/PicoAuth/LocalAuth.yml.

Additionaly, if password reset is enabled:

  • Write access to config/PicoAuth/data or write access to config/PicoAuth to create the data directory.

Rate limiting - permissions

If rate limiting is enabled, requires the following permissions:

  • Write access to config/PicoAuth/data or write access to config/PicoAuth to create the data directory.

Local user accounts

The module providing authentication with local user accounts is called LocalAuth and its configuration is located in config/PicoAuth/LocalAuth.yml. It can contain general configuration options, same as definition of user accounts.

Registered routes

Defining user accounts

The simplest way to define users is using the following syntax. The only required property that each record in users should have is pwhash, which is bcrypt by default.

users: 
  user1:
    pwhash: $2y$10$qi5Xz.39w3pvPw2k4BvanudOoelF/Li6necs1DoQUKFRLecvYpdKG
  user2:
    pwhash: $2y$10$KMWh.9YkxhhNqoMRBmNU5OnlerVSIJbmIckenlW.Llsa8a9G8wd32
    groups: [ employee ]

The groups attribute is optional, as every user is automatically a member of the default group.

Other user parameters that can be specified

  • encoder - Password hashing algorithm used to interpret the pwhash property.
  • pwreset - If set to true, the user will be requested to set a new password on the next login.
  • email - An email address that will be used to send password reset message to if password reset is enabled.
  • displayName - An alternative name for displaying, the theme template can prefer this version and use id as a fallback if not set
  • attributes - Any user-defined attributes that can then be accessed in Pico template (e.g. profile picture URL).
attributes:
  img: https://i.imgur.com/eiqj2hk.jpg

Registration

Registering new accounts is by default disabled. To enable it, set enabled: true under the registration section. Make sure that the path config/PicoAuth is writeable - the user files will be saved in config/PicoAuth/users directory. Read more about how to set up Write permissions.

registration:
  enabled: false
  nameLenMin: 3          # Minimum allowed length of a user name
  nameLenMax: 16         # Maximum allowed length of a user name
  maxUsers: 10000        # Maximum number of registered accounts in the system

Password change

Option for logged in users to change their password. Disabled by default. Same as for registrations, Write permissions must be configured.

accountEdit:
  enabled: false

Allowing password reset via email

If enabled, a user can request a password reset link to be sent to the email specified during a registration. This option is by default disabled. Enabling it requires Write permissions to be configured.

Mail sender must be configured for this function to work - see Setting up mail.

passwordReset:
  enabled: true
  emailSubject: "%site_title% - Password Reset"
  emailMessage: "Hello,\n\nVisit the link to reset your password to %site_title%.\n\nReset URL:\n%url%"
  tokenIdLen: 10        # Number of random bytes that make the reset token identifier
  tokenLen: 50          # Number of random bytes that make the reset token body
  tokenValidity: 7200   # Validity of the password reset link (seconds)
  resetTimeout: 3600    # Length of the reset session once a valid reset link is visited (seconds)

Fields emailSubject and emailMessage can contain Pico placeholders (like %site_title% or %base_url%). Additionally, emailMessage must contain a special %url% placeholder, which will be replaced with a full reset URL.

Password storage options

The default password hashing algorithm can be specified using the bcrypt key. This algorithm is used every time the user record does not have an encoder parameter set and is also used for new accounts. This can be set to argon2i if using PHP 7.2 with Argon2i support. Other algorithms and all algorithm parameters (like bcrypt cost) can be set in the Dependency container.

If the passwordRehash is enabled under the login section, a user's password is rehashed on login if it either doesn't use the preferred algorithm set in the global encoder settings, or if the parameters of the algorithm had changed since the current hash was created.

encoder: bcrypt
login:
  passwordRehash: true

OAuth 2.0

The module providing OAuth 2.0 sign is called OAuth and its configuration is located in config/PicoAuth/OAuth.yml. The main purpose of this file is to configure OAuth 2.0 service providers.

PicoAuth uses PHP League's OAuth 2.0 Client. To enable authentication using a specific service you must first install a Service provider for such a service (see a list of official providers and third party providers) or alternatively use a GenericProvider which uses Bearer token authentication. Both methods are shown in the example bellow:

1) Register an application by the OAuth 2.0 provider

First, you need to register a new application by the provider you are going to use in order to obtain clientId and clientSecret. The exact process differs from provider to provider, it should be described in a documentation of the particular service. Use the following:

  • Authorization Grant: authorization code (this is often implicit)
  • Callback URL: https://www.YourPicoSite.com/oauth_callback

The callback url is customizable, it can be customized by adding callbackPage: custom_callback to the OAuth.yml. Note: If your Pico installation does not have rewrite_url enabled, some providers may not accept callback url as /?oauth_callback and enabling url rewriting would be required.

2) Configure the provider in OAuth.yml

A) Using an existing service provider class

See if the provider you are going to use is listed either in the official providers or in the third party providers of the PHP League's OAuth client. If it is present, install it using composer in your Pico project. The example bellow will use a provider for Gitlab.com by Omines.

composer require omines/oauth2-gitlab

Note the provider class that will become available after the installation. For the example it is \Omines\OAuth2\Client\Provider\Gitlab. Now the provider can be configured in the config/PicoAuth/OAuth.yml:

providers:
  Gitlab:
    provider: '\Omines\OAuth2\Client\Provider\Gitlab'
    options:
      clientId: 'enter_client_id_from_step_1'
      clientSecret: 'enter_client_secret_from_step_1'

B) Using the GenericProvider

Many providers that use Bearer token authorization for the identity endpoint will work with the GenericProvider class (inluded in the League's OAuth client) and therefore without the need of requiring additional packages (for example when composer is not available). When the provider attribute is omitted, PicoAuth will automatically assume \League\OAuth2\Client\Provider\GenericProvider. Note that you need to specify all 3 required OAuth endpoints. The same functionality as in the step A can be achieved using:

providers:
  Gitlab:
    options:
      clientId: 'enter_client_id_from_step_1'
      clientSecret: 'enter_client_secret_from_step_1'
      urlAuthorize: 'https://gitlab.com/oauth/authorize'
      urlAccessToken: 'https://gitlab.com/oauth/token'
      urlResourceOwnerDetails: 'https://gitlab.com/api/v4/user'

3) Additional configuration

Attribute mapping

This can be used to map some attributes from the provider user info response to the user instance in PicoAuth. For example if the provider returns the following information about the user:

{
  "username": "john_smith",
  "name": "John Smith",
  "avatar_url": "http://provider/user/avatar/1554.jpg",
}

It can configured using this attributeMap option:

    attributeMap:
      userId: username
      displayName: name
      img: avatar_url
  • If the user object contained nested structures, they can be accessed using the dot notation like user.name.
  • userId and displayName have a special meaning to PicoAuth.
    • userId is the user identifier used to match user-based access rules. It can be displayed in Twig template using {{ auth.user.id }}
    • displayName can be displayed in Twig template using {{ auth.user.displayname }}
    • Any other attribute can be displayed using {{ auth.user.getAttribute("img") }}

Defining default properties

Default groups and default attributes can be specified for each provider:

    default:
      groups: [ providerSpecificGroup ]
      attributes:
        img: '/img/default-avatar.jpg'

4) Selecting the provider on login

If using the default PicoAuth template, a button will automatically appear on the /login page for each provider that has been configured.

Access control

The module providing authorization via access control rules is called PageACL and its configuration is located in config/PicoAuth/PageACL.yml.

Defining access rules

The access rules are defined under the access key. They are applied per page URL in Pico. URL definitions are case sensitive. Available options for rule definitions are:

  • users - an array of user names which can access the page.
  • groups - an array of groups with access to the page. A user having at least on group from the list will be granted access to view the page. Every authenticated user is member of the default group.
  • recursive - By default, all rules are matched recursively to all sub-pages, while preferring the most specific one to the evaluated URL (for example having rules for /a and /a/b, page /a/b/c will be matched with rule /a/b and rule /a will not be considered). This can be disabled by setting recursive: false for the specific rule - that way a rule won't apply to any other sub-page, but only on the exact match.

An example of config/PicoAuth/PageACL.yml:

access:
  /secret:
    groups: [default]     # Any authenticated user
  /secret/group:
    groups: [group]       # Any member of the "group"
  /secret/test:
    users: [test,user]    # Only the user "test" or "user"
  /:                      # This rule applies to the whole Pico site
    groups: [default]

Page locks

Page locks are a very simple way of access restriction and are independent on user authentication. A locked page will present a single input asking for a key and only a person with a knowledge of the key can unlock it and access the page. The module providing page locking is called PageLock and its configuration is located in config/PicoAuth/PageLock.yml.

Defining locks

Locks are defined separately from the pages they are applied to. A lock definition consists of its unique identifier and an unlock key.

locks:
  secret:
    key: $2y$10$KMWh.9YkxhhNqoMRBmNU5OnlerVSIJbmIckenlW.Llsa8a9G8wd32

By default, keys are expected to be Bcrypt hashes. An encoder attribute can be specified to override this option.

  lock1:
    key: "secret_key"
    encoder: plain

A custom file can be set to be displayed on the lock screen. It can contain an explanation why the page is locked or how to obtain the key to unlock it.

    file: locked_screen.md

Applying named locks to pages

Locks are applied to pages in the urls key. URLs are matched in the same way as in the PageACL module. URL definitions are case sensitive. Option to set recursive: false is also available.

Example of usage:

urls:
  /secret/locked:
    lock: secret
  /locked_A:
    lock: lock1
    recursive: false

Closing the session

In order to provide an option to lock all unlocked pages (close page locks session), the following button can be added to the template. This will lock all pages, but will not log out the user. The standard logout can be used as well if the user is authenticated, otherwise the logout route is not accessible.

<form method="POST" action="{{ current_page.url }}">
  {{ csrf_field() }}
  <button type="submit" name="logout-locks">Close session</button>
</form>

This form can be displayed only when some locks are actually unlocked in the current session, that can be checked in Twig using the following statement {% if auth.vars.locks is defined and auth.vars.locks is not empty %}...{% endif %}. This method is used in the picoauth-theme example.

Display the current user

PicoAuth variables are accessible form the Twig template under the prefix auth. The current user can be accessed under auth.user. This variable is always set, the authentication flag is under auth.user.authenticated. Other varialbes include:

  • auth.user.id - user identifier, always set if authenticated, otherwise null
  • auth.user.displayname - display name if available, otherwise null
  • auth.user.authenticator - name of the method the user authenticated with
  • auth.user.groups - array of groups the user is member of
  • auth.user.getAttribute("key") - gets the key attribute of the user object, returns null if not set

Displaying the current user and providing and option to log out is a basic functionality that should be added to your current theme.

{% if auth.user.authenticated %}
    <strong>{{ auth.user.id }}</strong>
    | <form method="POST" action="{{ "logout"|link }}" class="inline">
        {{ csrf_field("logout") }}
        <input type="submit" value="Logout" name="logout" class="link">
    </form>
{% else %}
    <a href="{{ "login"|link }}">Login</a>
{% endif %}

Showing the display name if available

The display name is a friendly representation of the user's name, but depending on the method the user has authenticated it may not be always available.

{% if auth.user.displayname %}
    <strong>{{ auth.user.displayname }}</strong> ({{ auth.user.id }})
{% else %}
    <strong>{{ auth.user.id }}</strong>
{% endif %}

Working with custom user attributes

The following example can be used to display user's profile picture:

{% if auth.user.getAttribute("img") %}
    <img class="profile" src="{{auth.user.getAttribute("img")}}">
{% endif %}

Accessing plugin's configuration

It is good to display some parts only if they should be displayed - an example is the registration link, which depends on the plugin's configurtion.

{% if auth.plugin.getModule("localAuth").config.registration.enabled %}
    <a href="{{ "register"|link }}">Register</a>
{% endif %}

Other examples

The complete example of PicoAuth integration into a template is picoauth-template.

Overriding the default theme

By default, PicoAuth renders forms (like login, registration, password change, etc.) using its own theme supplied with the plugin. This can be used, but for better and more fluent user experience it is good to integrate the authentication forms to your current theme. This can be done by placing the customized form templates to your theme directory. If a form theme is found in the current theme directory, it takes precedence over the default theme located in the plugin's directory.

To see what templates can be overridden, refer to the PicoAuth/theme directory.

Overriding the base template

The simplest way is to customize only the base template, which is extended by all other PicoAuth templates. That way the structure of the forms will stay as default, but they will be placed into your custom template. PicoAuth base template is called picoAuth_base.twig. If providing a custom base template, make sure to include {{ block("body") }}, which is the place where the page content gets inserted to.

After the file picoAuth_base.twig is added to your template files, you will probably need to adjust your template's CSS to display the default forms properly.

Overriding individual templates

If you need to edit the individual forms copy the form template you want to customize from /plugins/PicoAuth/theme to /themes/your-theme and edit the form as required. All forms contain a hidden CSRF field - make sure to keep this part intact when customizing the forms. Example of the field item for the login form:

{{ csrf_field("login") }}

The dependency container

PicoAuth uses \League\Container\Container as its dependency injection container. The container definition can be customized by the user of the plugin to allow broader options for customizations and an advanced configuration.

Obtaining a copy of the container definition

The container definition is located in PicoAuth/src/container.php. Avoid editing the file at this location to allow for non-conflicting updates. Instead, copy the file to the PicoAuth configuration directory - config/PicoAuth/container.php. If the file is present in the configuration directory, PicoAuth will use it instead of the default definition.

Rate limiting

Rate limiting can be used to limit the maximum number of critical operations (bad login attempts, password reset requests, registrations, ...) to prevent brute-force attacks or system flooding. The configuration is located in config/PicoAuth/RateLimit.yml.

Enable/disable rate limiting

Rate limiting can be enabled or disabled in the main configuration file of Pico (config/config.yml), under the key rateLimit in the PicoAuth properties:

PicoAuth:
  rateLimit: true

Enabling it requires Write permissions to be configured.

Rate limiting parameters

Rate limiting parameters can be configured in config/PicoAuth/RateLimit.yml. Actions can be usually limited by 2 limit types - limit per IP subnet and limit per the entity the action was performed on. This will be explained on the example of the login rate limit:

actions:
  login:
    ip:
      count: 100
      counterTimeout: 43200
      blockDuration: 900
      netmask_IPv4: 32
      netmask_IPv6: 64
    account:
      count: 20
      counterTimeout: 43200
      blockDuration: 900

This would mean that:

  • 1 IPv4 address or /64 subnet of IPv6 can submit 100 incorrect login attempts (for any combination of user name and password).
  • 20 incorrect login attempts can be made on a specific user account.
  • After any of the limits is reached, the IP or the account will be blocked for 900 seconds.
  • Alternatively, if 43200 seconds passes from the last attempt and the limit is not reached, the internal counter is reset.

Supported actions for rate limiting

Here is the list of actions and rate limit types that can be applied on them:

  • login - ip, account - number of incorrect login attempts
  • passwordReset - ip, email - number of password reset requests
  • registration - ip - number of registered accounts
  • pageLock - ip - number of incorrect attempts for page unlock

Providing custom error message

A custom error message can be provided in the errorMsg attribute. Such a message can contain place holder strings that will be replaced with the details about the reached limit:

  • %cnt% - The maximum number of actions that is allowed.
  • %min% - An amount of minutes of the block duration.

The custom error message can be seen for example in the passwordReset limit:

  passwordReset:
    email:
      count: 3
      counterTimeout: 86400
      blockDuration: 86400
      errorMsg: 'Maximum of %cnt% reset emails were sent, check your inbox.'

The default configuration

The default configuration for rate limiting is located in /src/Storage/Configurator/RateLimitConfigurator.php. The default values are populated per action. That means if you'd want to keep defaults only for the login action and deactivate rate limiting for all other actions, the configuration file would look like this:

actions:
  passwordReset: []
  registration: []
  pageLock: []

Storage options

By default, the data files for rate limiting are being saved as a php-serialized text files into config/PicoAuth/data directory. The performance may not be sufficient for thousands of records. However, it is possible to use SQLite 3 for this storage if sqlite3 PHP module is available. To use this option, modify the dependency container configuration and replace RateLimitFileStorage with RateLimitSqliteStorage.

Set up logging

Enabling logging in PicoAuth is recommended for monitoring any potential errors, intrusion attempts, interesting events and debugging information.

1) Prepare the container.php for editing

Cache configuration requires changes in the plugin's dependency container. See the section about Customizing the dependency container.

2) Installing the logger implementation

PicoAuth can use any logger implementation adhering to the Psr\Log\LoggerInterface. Select the implementation you want to use and require it using composer in your Pico installation.

Example:

composer require monolog/monolog

3) Add the logger driver to the container.php

Open the config/PicoAuth/container.php and scroll down to the Logger configuration section. Insert the Fully-Qualified Class Name of the adapter under the logger key in the container definition.

$log = new \Monolog\Logger('name');
$log->pushHandler(...); // Configure the logger
$container->share('logger', $log);

4) Customize logging origins

Every class with support of logging will have ->withMethodCall('setLogger', ['logger']) statement in the container definition. To disable logging from a particular class, this call can be removed. It can be also used to provide different logger instances to different parts of the application.

Logged events

Event origin Level Description
LocalAuth Notice Invalid login attempt
LocalAuth - PasswordReset Info Password reset email sent
LocalAuth - PasswordReset Info Valid reset link visited
LocalAuth - PasswordReset Info Completed password reset
LocalAuth - PasswordReset Warning Invalid reset token
LocalAuth - PasswordReset Critical Sending mail but no mailer is set
LocalAuth - PasswordReset Critical Mailer error
LocalAuth - Registration Info New registration
LocalAuth - Registration Warning On each 10% of the maximum users count
OAuth Notice OAuth2 error response code
OAuth Warning OAuth2 response state mismatch
OAuth Critical OAuth2 IdentityProviderException
RateLimit Notice Rate limit reached
PicoAuthPlugin Info Successful login via any authenticator
PicoAuthPlugin Warning Any submission with wrong CSRF token
PicoAuthPlugin Critical An exception from any module

Configure cache

PicoAuth configuration files are parsed and validated on each request. Usually this operation doesn't take a long time as the files are small. However, a configuration cache can be set up to speed up the processing.

1) Prepare the container.php for editing

Cache configuration requires changes in the plugin's dependency container. See the section about Customizing the dependency container.

2) Installing the cache implementation

PicoAuth can use any cache implementation adhering to the Psr\SimpleCache\CacheInterface. Project php-cache provides many implementations (like Apcu, Memcached, Redis). Select the implementation you want to use and require it using composer in your Pico installation.

Example:

composer require cache/apcu-adapter

3) Add the cache driver to the container.php

Open the config/PicoAuth/container.php and scroll down to the Cache configuration section. Insert the Fully-Qualified Class Name of the adapter under the cache key in the container definition.

$pool = new \Cache\Adapter\Apcu();
$container->share('cache', $pool);

Password policy

A password policy can be used to require certain complexity of user passwords.

1) Prepare the container.php for editing

Password policy configuration requires changes in the plugin's dependency container. See the section about Customizing the dependency container.

2) Setting up password policy constraints

Open the config/PicoAuth/container.php and scroll down to the Password policy configuration section. This is the default configuration:

$container->share('PasswordPolicy', 'PicoAuth\Security\Password\Policy\PasswordPolicy')
    ->withMethodCall('minLength', [new RawArgument(8)]);

More constraints can be added by additional withMethodCall calls:

$container->share('PasswordPolicy', 'PicoAuth\Security\Password\Policy\PasswordPolicy')
    ->withMethodCall('minLength', [new RawArgument(8)])
    ->withMethodCall('minNumbers', [new RawArgument(1)])
    ->withMethodCall('minUppercase', [new RawArgument(1)])
    ->withMethodCall('minSpecial', [new RawArgument(1)])
    ->withMethodCall('matches', [new RawArgument('/(?=^.{8,}$)/'), new RawArgument('Minimum length is 8 characters.')]);

Supported constraints are:

  • minLength - shortest allowed password length
  • minNumbers - a minimum amount of numbers contained in a password
  • minUppercase - a minimum amount of upper case letters contained in a password
  • minSpecial - a minimum number of special characters contained in a password
  • matches - a regular expression that the password must match, with a message that will be presented if the condition fails

Using an alternative enforcer

An alternative password policy enforcer can be used by providing an implementation of PicoAuth\Security\Password\Policy\PasswordPolicyInterface and adding it to the container definition.

Sending mail

If the password reset option is enabled, a way to handle outgoing mail should be configured. It is up to the user of the plugin what way is used is to send the mail.

1) Prepare the container.php for editing

Mailer configuration requires changes in the plugin's dependency container. See the section about Customizing the dependency container.

2) Providing Mailer implementation

PicoAuth uses a very simple interface PicoAuth\Mail\MailerInterface to send out mail. Any class implementing this interface can be set in the container definition - locate the Mail setup in your container.php. Example of setting the mail implementation:

include 'Mailer.php';
$container->share('mailer','PicoAuth\Mail\Mailer');

The Mailer.php is a PHP class located in config/PicoAuth/Mailer.php. After the mailer is set, make sure that the PasswordReset class has it injected with ->withMethodCall('setMailer',['mailer']) call.

Mailer examples

The following examples of Mailer.php use PHPMailer, which can be installed using composer require phpmailer/phpmailer.

Sendmail eample

<?php
namespace PicoAuth\Mail;

class Mailer implements \PicoAuth\Mail\MailerInterface {

    protected $mail;

    public function setup() {
        $this->mail = new \PHPMailer\PHPMailer\PHPMailer;
        $this->mail->isSendmail();
        $this->mail->setFrom('noreplay@example.com', 'PicoAuth');
    }

    public function setTo($mail) {
        $this->mail->addAddress($mail);
    }

    public function setSubject($subject) {
        $this->mail->Subject = $subject;
    }

    public function setBody($body) {
        $this->mail->Body = $body;
    }

    public function send() {
        return $this->mail->send();
    }

    public function getError() {
        return $this->mail->ErrorInfo;
    }
}

SMTP example

Only the setup method would differ from the previous example:

    public function setup() {
        $this->mail = new \PHPMailer\PHPMailer\PHPMailer;

        $this->mail->isSMTP();
        $this->mail->Host = 'smtp.example.com';    // Specify SMTP server
        $this->mail->SMTPAuth = true;              // Enable SMTP authentication
        $this->mail->Username = '...';             // SMTP username
        $this->mail->Password = '...';             // SMTP password
        $this->mail->SMTPSecure = 'ssl';           // Enable encryption
        $this->mail->Port = 465;                   // SMTP port
        $this->mail->From = 'noreply@example.com'; // The address sending the email 
        $this->mail->FromName = 'PicoAuth';        // The name field
    }

Other options

Refer to the documentation of the mailing library/platform for other examples of sending mail.

Session parameters

PicoAuth uses Symfony Session Component for its session management. An alternative session manager can be used if an adapter is provided for it that implements PicoAuth\Session\SessionInterface. Session management configuration is described in the following steps.

1) Prepare the container.php for editing

Session managment configuration requires changes in the plugin's dependency container. See the section about Customizing the dependency container.

2) Changing SessionStorage options

Session configuration is located in config/PicoAuth/container.php under the Session management configuration section. Documentation about the session configuration can be found in the Symfony Session Docs and PHP Documentation about sessions. The session parameters that are included by default are:

  • cookie_lifetime - 0 - session cookie lifetime until the browser is closed
  • gc_maxlifetime - 7200 - activity time out of the session is set to 2hrs
  • name - Pico - session cookie name
  • cookie_httponly - 1 - session cookie not readable from
  • cookie_secure - 0 - set to 1 if using HTTPS