Password encoders

Available:

Crowd 1.5 and later

This module type allows you to define your own password encoders for Crowd.

For example, say you want to implement a CRYPT password encoder.

Your atlassian-plugin.xml would look like this:

1
2
3
4
5
6
7
8
9
10
11
12
<atlassian-plugin name="Custom Password Encoders" key="mycompany.crowd.passwordencoders" system="false">
    <plugin-info>
        <description>Custom password encoders to work with my custom directory store</description>
        <vendor name="Atlassian Software Systems" url="http://www.atlassian.com"/>
        <version>1.0</version>
    </plugin-info>

    <encoder key="crypt" name="Crypt Password Encoder" class="com.atlassian.crowd.password.encoder.CryptPasswordEncoder">
        <description>CRYPT based encoder</description>
    </encoder>

</atlassian-plugin>

Your com.atlassian.crowd.password.encoder.CryptPasswordEncoder will need to implement one or both of the following interfaces:

  • com.atlassian.crowd.password.encoder.LdapPasswordEncoder
  • com.atlassian.crowd.password.encoder.InternalPasswordEncoder

These two interfaces extend a parent interface com.atlassian.crowd.password.encoder.PasswordEncoder. This interface may look very familiar if you have spent some time in the Spring Security source.CROWD:1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.atlassian.crowd.password.encoder;

import com.atlassian.crowd.exception.PasswordEncoderException;

/**
 * <p>Defines the operations and requirements for a class that needs to handle password
 * operations in Crowd</p>
 * Some of the  below documentation is taken from Spring Security
 */
public interface PasswordEncoder
{

    /**
     * <p>Encodes the specified raw password with an implementation specific algorithm.</p>
     * <P>This will generally be a one-way message digest such as MD5 or SHA, but may also be a plaintext
     * variant which does no encoding at all, but rather returns the same password it was fed. The latter is useful to
     * plug in when the original password must be stored as-is.</p>
     * <p>The specified salt will potentially be used by the implementation to "salt" the initial value before
     * encoding. A salt is usually a user-specific value which is added to the password before the digest is computed.
     * This means that computation of digests for common dictionary words will be different than those in the backend
     * store, because the dictionary word digests will not reflect the addition of the salt. If a per-user salt is
     * used (rather than a system-wide salt), it also means users with the same password will have different digest
     * encoded passwords in the backend store.</p>
     * <P>If a salt value is provided, the same salt value must be use when calling the  {@link
     * #isPasswordValid(String, String, Object)} method. Note that a specific implementation may choose to ignore the
     * salt value (via <code>null</code>), or provide its own.</p>
     *
     * @param rawPass the password to encode
     * @param salt    optionally used by the implementation to "salt" the raw password before encoding. A
     *                <code>null</code> value is legal.
     * @return encoded password
     * @throws PasswordEncoderException if there were any issues trying to encode a password
     */
    String encodePassword(String rawPass, Object salt) throws PasswordEncoderException;

    /**
     * <p>Validates a specified "raw" password against an encoded password.</p>
     * <P>The encoded password should have previously been generated by {@link #encodePassword(String,
     * Object)}. This method will encode the <code>rawPass</code> (using the optional <code>salt</code>),  and then
     * compared it with the presented <code>encPass</code>.</p>
     * <p>For a discussion of salts, please refer to {@link #encodePassword(String, Object)}.</p>
     *
     * @param encPass a pre-encoded password
     * @param rawPass a raw password to encode and compare against the pre-encoded password
     * @param salt    optionally used by the implementation to "salt" the raw password before encoding. A
     *                <code>null</code> value is legal.
     * @return true if the password is valid , false otherwise
     */
    boolean isPasswordValid(String encPass, String rawPass, Object salt);

    /**
     * The key to define this password encoder
     * @return
     */
    String getKey();
}

These two interfaces are marker interfaces that will determine whether or not your plugin will appear in the password encoder dropdown list which appears when a Crowd administrator adds an LDAP-based directory or an Internal directory.

Developing Plugins for Crowd

1 A big thanks to Ben Alex and the Spring Security team.