<?xml version="1.0" encoding="UTF-8"?>
<!--
! CCPL HEADER START
!
! This work is licensed under the Creative Commons
! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
! To view a copy of this license, visit
! http://creativecommons.org/licenses/by-nc-nd/3.0/
! or send a letter to Creative Commons, 444 Castro Street,
! Suite 900, Mountain View, California, 94041, USA.
!
! You can also obtain a copy of the license at
! trunk/opendj3/legal-notices/CC-BY-NC-ND.txt.
! See the License for the specific language governing permissions
! and limitations under the License.
!
! If applicable, add the following below this CCPL HEADER, with the fields
! enclosed by brackets "[]" replaced with your own identifying information:
! Portions Copyright [yyyy] [name of copyright owner]
!
! CCPL HEADER END
!
! Copyright 2011-2015 ForgeRock AS.
!
-->
<chapter xml:id='chap-account-lockout'
xmlns='http://docbook.org/ns/docbook' version='5.0' xml:lang='en'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://docbook.org/ns/docbook
http://docbook.org/xml/5.0/xsd/docbook.xsd'
xmlns:xlink='http://www.w3.org/1999/xlink'>
<title>Implementing Account Lockout &amp; Notification</title>
<para>OpenDJ directory server supports automatic account lockout.
The aim of account lockout is not to punish users who mistype their
passwords, but instead to protect the directory against attacks
in which the attacker attempts to guess a user password, repeatedly
attempting to bind until success is achieved.</para>
<para>Account lockout disables a user account after a specified
number of successive authentication failures. When you implement account
lockout, you can opt to have OpenDJ directory server unlock the account
again after a specified interval, or you can leave the account locked
until the password is reset.</para>
<note>
<para>When you configure account lockout as part of password policy, OpenDJ
locks an account after the specified number of consecutive authentication
failures. Account lockout is not transactional across a replication topology,
however. Under normal circumstances, replication nevertheless propagates
lockout quickly. If ever replication is delayed, an attacker with direct
access to multiple replicas could try to authenticate up to the specified
number of times on each replica before being locked out on all replicas.</para>
</note>
<para>
This chapter shows you how to set up account lockout policies by using the
<link
xlink:show="new"
xlink:href="reference#dsconfig-1"
xlink:role="http://docbook.org/xlink/role/olink"
><command>dsconfig</command></link> command,
and how to intervene manually to lock and unlock accounts by using the
<link
xlink:show="new"
xlink:href="reference#manage-account-1"
xlink:role="http://docbook.org/xlink/role/olink"
><command>manage-account</command></link> command.
</para>
<section xml:id="configure-account-lockout">
<title>Configuring Account Lockout</title>
<indexterm><primary>Accounts</primary><secondary>Lockout</secondary></indexterm>
<para>Account lockout is configured as part of password policy. This section
demonstrates configuring account lockout as part of the default password
policy. Users are allowed three consecutive failures before being locked out
for five minutes. Failures themselves also expire after five minutes.</para>
<para>Change the default password policy to activate lockout using the
<command>dsconfig</command> command. As the password policy is part of
the server configuration, you must manually apply the changes to each
replica in a replication topology.</para>
<screen>
$ <userinput>dsconfig \
set-password-policy-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--policy-name "Default Password Policy" \
--set lockout-failure-count:3 \
--set lockout-duration:5m \
--set lockout-failure-expiration-interval:5m \
--trustAll \
--no-prompt</userinput>
</screen>
<para>Users having the default password policy are then locked out after
three failed attempts in succession.</para>
<screen>
$ <userinput>ldapsearch \
--port 1389 \
--bindDN "uid=bjensen,ou=people,dc=example,dc=com" \
--bindPassword hifalutin \
--baseDN dc=example,dc=com \
uid=bjensen \
mail</userinput>
<computeroutput>dn: uid=bjensen,ou=People,dc=example,dc=com
mail: bjensen@example.com</computeroutput>
$ <userinput>ldapsearch \
--port 1389 \
--bindDN "uid=bjensen,ou=people,dc=example,dc=com" \
--bindPassword fatfngrs \
--baseDN dc=example,dc=com \
uid=bjensen \
mail</userinput>
<computeroutput>The simple bind attempt failed
Result Code: 49 (Invalid Credentials)</computeroutput>
$ <userinput>ldapsearch \
--port 1389 \
--bindDN "uid=bjensen,ou=people,dc=example,dc=com" \
--bindPassword fatfngrs \
--baseDN dc=example,dc=com \
uid=bjensen \
mail</userinput>
<computeroutput>The simple bind attempt failed
Result Code: 49 (Invalid Credentials)</computeroutput>
$ <userinput>ldapsearch \
--port 1389 \
--bindDN "uid=bjensen,ou=people,dc=example,dc=com" \
--bindPassword fatfngrs \
--baseDN dc=example,dc=com \
uid=bjensen \
mail</userinput>
<computeroutput>The simple bind attempt failed
Result Code: 49 (Invalid Credentials)</computeroutput>
$ <userinput>ldapsearch \
--port 1389 \
--bindDN "uid=bjensen,ou=people,dc=example,dc=com" \
--bindPassword hifalutin \
--baseDN dc=example,dc=com \
uid=bjensen \
mail</userinput>
<computeroutput>The simple bind attempt failed
Result Code: 49 (Invalid Credentials)</computeroutput>
</screen>
</section>
<section xml:id="manage-accounts">
<title>Managing Accounts Manually</title>
<para>This section covers disabling and enabling accounts by using the
<command>manage-account</command> command. Password reset is covered in
the chapter on performing LDAP operations.</para>
<para>For the following examples, the directory admin user, Kirsten Vaughan,
has <literal>ds-privilege-name: password-reset</literal>, and the following
ACI on <literal>ou=People,dc=example,dc=com</literal>.</para>
<programlisting language="aci">
(target="ldap:///ou=People,dc=example,dc=com") (targetattr ="*||+")(
version 3.0;acl "Admins can run amok"; allow(all) groupdn =
"ldap:///cn=Directory Administrators,ou=Groups,dc=example,dc=com";)
</programlisting>
<procedure xml:id="disable-account">
<title>To Disable an Account</title>
<indexterm>
<primary>Accounts</primary>
<secondary>Disabling</secondary>
</indexterm>
<step>
<para>Set the account status to disabled with the
<command>manage-account</command> command.</para>
<screen>
$ <userinput>manage-account \
set-account-is-disabled \
--port 4444 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
--operationValue true \
--targetDN uid=bjensen,ou=people,dc=example,dc=com \
--trustAll</userinput>
<computeroutput>Account Is Disabled: true</computeroutput>
</screen>
</step>
</procedure>
<procedure xml:id="reactivate-account">
<title>To Activate a Disabled Account</title>
<indexterm>
<primary>Accounts</primary>
<secondary>Activating</secondary>
</indexterm>
<step>
<para>Clear the disabled status using the <command>manage-account</command>
command.</para>
<screen>
$ <userinput>manage-account \
clear-account-is-disabled \
--port 4444 \
--bindDN "uid=kvaughan,ou=people,dc=example,dc=com" \
--bindPassword bribery \
--targetDN uid=bjensen,ou=people,dc=example,dc=com \
--trustAll</userinput>
<computeroutput>Account Is Disabled: false</computeroutput>
</screen>
</step>
</procedure>
</section>
<section xml:id="account-status-notification">
<title>Managing Account Status Notification</title>
<indexterm>
<primary>Accounts</primary>
<secondary>Status notifications</secondary>
</indexterm>
<para>OpenDJ can send mail about account status changes. OpenDJ needs an
SMTP server to send messages, and needs templates for the mail it sends.
By default, message templates are in English, under
<filename>/path/to/opendj/config/messages/</filename>.</para>
<para>OpenDJ generates notifications only when OpenDJ writes to an entry or
evaluates a user entry for authentication. OpenDJ generates account enabled
and account disabled notifications when the user account is enabled or
disabled with the <command>manage-account</command> command, which writes
to the entry. OpenDJ generates password expiration notifications when a
user tries to bind.</para>
<para>For example, if you set up OpenDJ to send a notification about password
expiration, that notification gets triggered when the user authenticates
during the password expiration warning interval. OpenDJ does not
automatically scan entries to send password expiry notifications. OpenDJ does
implement controls that you can pass in an LDAP search to determine whether a
user's password is about to expire. See the appendix on
<link xlink:href="reference#appendix-controls" xlink:show="new"
xlink:role="http://docbook.org/xlink/role/olink"><citetitle>LDAP
Controls</citetitle></link> for a list. You can send notifications then
based on the results of your search.</para>
<procedure xml:id="mail-account-status-notifications">
<title>To Mail Users About Account Status</title>
<para>The following steps demonstrate how to set up notifications. Whether
OpenDJ sends notifications depends on the settings in the password policy,
and on account activity as described above.</para>
<step>
<para>Identify the SMTP server to which OpenDJ sends messages.</para>
<screen>
$ <userinput>dsconfig \
set-global-configuration-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--set smtp-server:smtp.example.com \
--trustAll \
--no-prompt</userinput>
</screen>
</step>
<step>
<para>Set up OpenDJ to be able to mail users about account status.</para>
<screen>
$ <userinput>dsconfig \
set-account-status-notification-handler-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--handler-name "SMTP Handler" \
--set enabled:true \
--set email-address-attribute-type:mail \
--trustAll \
--no-prompt</userinput>
</screen>
<para>Notice that OpenDJ finds the user's mail address on the attribute
on the user's entry, specified by
<literal>email-address-attribute-type</literal>.</para>
<para>You can also configure the <literal>message-subject</literal> and
<literal>message-template-file</literal> properties. Try interactive
mode if you plan to do so.</para>
<para>You find templates for messages by default under the
<filename>config/messages</filename> directory. You can edit the templates
to suit your purposes.</para>
</step>
<step>
<para>Adjust applicable password policies to use the account status
notification handler you configured.</para>
<screen>
$ <userinput>dsconfig \
set-password-policy-prop \
--port 4444 \
--hostname opendj.example.com \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--policy-name "Default Password Policy" \
--set account-status-notification-handler:"SMTP Handler" \
--trustAll \
--no-prompt</userinput>
</screen>
</step>
</procedure>
<variablelist xml:id="about-message-templates">
<title>About Notification Message Templates</title>
<indexterm>
<primary>Accounts</primary>
<secondary>Customizing notification messages</secondary>
</indexterm>
<para>When editing the <filename>config/messages</filename> templates
to suit your purposes, you can use the following tokens to have OpenDJ
update the message text dynamically.</para>
<varlistentry>
<term><literal>%%notification-type%%</literal></term>
<listitem>
<para>This token is replaced with the name of the account status
notification type for the notification.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>%%notification-message%%</literal></term>
<listitem>
<para>This token is replaced with the message for the account status
notification.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>%%notification-user-dn%%</literal></term>
<listitem>
<para>This token is replaced with the string representation of the DN for
the user that is the target of the account status notification.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>%%notification-user-attr:<replaceable>attrname</replaceable>%%</literal></term>
<listitem>
<para>This token is replaced with the value of the attribute specified by
<replaceable>attrname</replaceable> from the user's entry. If the
specified attribute has multiple values, then OpenDJ uses the first value
encountered. If the specified attribute does not have any values, then
OpenDJ replaces it with an emtpy string.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>%%notification-property:<replaceable>propname</replaceable>%%</literal></term>
<listitem>
<para>This token is replaced with the value of the specified notification
property from the account status notification. If the specified property
has multiple values, then OpenDJ uses the first value encountered. If the
specified property does not have any values, then OpenDJ replaces it with
an emtpy string. Valid <replaceable>propname</replaceable> values include
the following.</para>
<itemizedlist>
<listitem><para><literal>account-unlock-time</literal></para></listitem>
<listitem><para><literal>new-password</literal></para></listitem>
<listitem><para><literal>old-password</literal></para></listitem>
<listitem><para><literal>password-expiration-time</literal></para></listitem>
<listitem><para><literal>password-policy-dn</literal></para></listitem>
<listitem><para><literal>seconds-until-expiration</literal></para></listitem>
<listitem><para><literal>seconds-until-unlock</literal></para></listitem>
<listitem><para><literal>time-until-expiration</literal></para></listitem>
<listitem><para><literal>time-until-unlock</literal></para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
</variablelist>
</section>
</chapter>