Is Shiro DefaultPasswordService thread safe?

Can I have one instance DefaultPasswordServiceand call its method encryptPassword()without worrying about thread safety issues?

This is not done in the documentation.

+4
source share
3 answers

It is safe. I created a trace of all protocol calls and simultaneously accessible fields from the following test class:

public class TestShiro  implements Runnable {

private static final DefaultPasswordService defaultPasswordService = new DefaultPasswordService();

protected void exec() {
/*  calling 
 * defaultPasswordService.setHashFormat(   new Shiro1CryptFormat() ); 
 * will lead to a data race
 */
    defaultPasswordService.encryptPassword( Thread.currentThread().getName());

}

private AtomicInteger threadCount = new AtomicInteger();

public void test() throws Exception
{
    for(int i = 0; i < 8 ;i++)
    {
        Thread thread = new Thread(this, "First Test Thread " + i);
        this.threadCount.incrementAndGet();
        thread.start();
    }


    while( this.threadCount.get() > 0 )
    {
        Thread.sleep(1000);
    }


    Thread.sleep(10 * 1000);
}


public void run()
{
    exec();
    threadCount.decrementAndGet();

}

public static void main(String[] args) throws Exception
{
     (new TestShiro()).test();
}
}

The trace for one thread is as follows:

com.anarsoft.agent.regression.MultiThreadedOneInstanceTemplate.run
com.anarsoft.agent.regression.TestShiro.exec
org.apache.shiro.authc.credential.DefaultPasswordService.encryptPassword
org.apache.shiro.authc.credential.DefaultPasswordService.hashPassword
org.apache.shiro.authc.credential.DefaultPasswordService.createByteSource
org.apache.shiro.util.ByteSource$Util.bytes
org.apache.shiro.util.ByteSource$Util.isCompatible
org.apache.shiro.util.SimpleByteSource.<init>
org.apache.shiro.codec.CodecSupport.toBytes
org.apache.shiro.codec.CodecSupport.toBytes
org.apache.shiro.authc.credential.DefaultPasswordService.createHashRequest
org.apache.shiro.crypto.hash.SimpleHashRequest.<init>
org.apache.shiro.authc.credential.DefaultPasswordService.hashPassword
    read  from field  org.apache.shiro.authc.credential.DefaultPasswordService.hashService from object 861842890
org.apache.shiro.crypto.hash.SimpleHashRequest.<init>
org.apache.shiro.crypto.hash.DefaultHashService.computeHash
org.apache.shiro.crypto.hash.DefaultHashService.getAlgorithmName
org.apache.shiro.crypto.hash.DefaultHashService.getHashAlgorithmName
    read  from field  org.apache.shiro.crypto.hash.DefaultHashService.algorithmName from object 1033490990
org.apache.shiro.crypto.hash.DefaultHashService.getAlgorithmName
org.apache.shiro.crypto.hash.DefaultHashService.getIterations
org.apache.shiro.crypto.hash.DefaultHashService.getHashIterations
    read  from field  org.apache.shiro.crypto.hash.DefaultHashService.iterations from object 1033490990
org.apache.shiro.crypto.hash.DefaultHashService.getIterations
org.apache.shiro.crypto.hash.DefaultHashService.getPublicSalt
org.apache.shiro.crypto.hash.DefaultHashService.getPrivateSalt
    read  from field  org.apache.shiro.crypto.hash.DefaultHashService.privateSalt from object 1033490990
org.apache.shiro.crypto.hash.DefaultHashService.isGeneratePublicSalt
    read  from field  org.apache.shiro.crypto.hash.DefaultHashService.generatePublicSalt from object 1033490990
org.apache.shiro.crypto.hash.DefaultHashService.getRandomNumberGenerator
    read  from field  org.apache.shiro.crypto.hash.DefaultHashService.rng from object 1033490990
org.apache.shiro.crypto.hash.DefaultHashService.getPublicSalt
org.apache.shiro.crypto.SecureRandomNumberGenerator.nextBytes
org.apache.shiro.crypto.SecureRandomNumberGenerator.getDefaultNextBytesSize
    read  from field  org.apache.shiro.crypto.SecureRandomNumberGenerator.defaultNextBytesSize from object 520016214
org.apache.shiro.crypto.SecureRandomNumberGenerator.nextBytes
org.apache.shiro.crypto.SecureRandomNumberGenerator.nextBytes
org.apache.shiro.crypto.SecureRandomNumberGenerator.nextBytes
    read  from field  org.apache.shiro.crypto.SecureRandomNumberGenerator.secureRandom from object 520016214
org.apache.shiro.crypto.hash.DefaultHashService.getPrivateSalt
    read  from field  org.apache.shiro.crypto.hash.DefaultHashService.privateSalt from object 1033490990
org.apache.shiro.crypto.SecureRandomNumberGenerator.nextBytes
org.apache.shiro.crypto.hash.DefaultHashService.combine
org.apache.shiro.crypto.hash.SimpleHash.<init>
org.apache.shiro.util.StringUtils.hasText
org.apache.shiro.util.StringUtils.hasLength
org.apache.shiro.crypto.hash.SimpleHash.convertSaltToBytes
org.apache.shiro.crypto.hash.SimpleHash.toByteSource
org.apache.shiro.crypto.hash.SimpleHash.convertSourceToBytes
org.apache.shiro.crypto.hash.SimpleHash.toByteSource
org.apache.shiro.crypto.hash.SimpleHash.hash
org.apache.shiro.crypto.hash.SimpleHash.hash
org.apache.shiro.crypto.hash.SimpleHash.getDigest
java.util.HashMap.getNode
    read  from field  java.util.HashMap.table from object 832279283
java.util.HashMap.getNode
    read  from field  java.util.HashMap$Node.hash from object 22805895
java.util.HashMap.getNode
    read  from field  java.util.HashMap$Node.key from object 22805895
java.util.LinkedHashMap.get
    read  from field  java.util.LinkedHashMap.accessOrder from object 832279283
java.util.LinkedHashMap.get
    read  from field  java.util.HashMap$Node.value from object 22805895
java.util.HashMap.getNode
    read  from field  java.util.HashMap.table from object 1924582348
java.util.HashMap.getNode
    read  from field  java.util.HashMap$Node.hash from object 2097514481
java.util.HashMap.getNode
    read  from field  java.util.HashMap$Node.key from object 2097514481
java.util.HashMap.get
    read  from field  java.util.HashMap$Node.value from object 2097514481
org.apache.shiro.crypto.hash.SimpleHash.getDigest
org.apache.shiro.crypto.hash.SimpleHash.setIterations
org.apache.shiro.authc.credential.DefaultPasswordService.checkHashFormatDurability
org.apache.shiro.authc.credential.DefaultPasswordService.checkHashFormatDurability
    read  from field  org.apache.shiro.authc.credential.DefaultPasswordService.hashFormatWarned from object 861842890
org.apache.shiro.authc.credential.DefaultPasswordService.checkHashFormatDurability
    read  from field  org.apache.shiro.authc.credential.DefaultPasswordService.hashFormat from object 861842890
org.apache.shiro.authc.credential.DefaultPasswordService.encryptPassword
    read  from field  org.apache.shiro.authc.credential.DefaultPasswordService.hashFormat from object 861842890
org.apache.shiro.authc.credential.DefaultPasswordService.checkHashFormatDurability
org.apache.shiro.crypto.hash.format.Shiro1CryptFormat.format
org.apache.shiro.util.SimpleByteSource.toBase64
org.apache.shiro.codec.Base64.encodeToString
org.apache.shiro.codec.Base64.encode
org.apache.shiro.codec.Base64.encode
org.apache.shiro.codec.CodecSupport.toString
org.apache.shiro.codec.CodecSupport.toString
org.apache.shiro.crypto.hash.SimpleHash.toBase64
org.apache.shiro.codec.Base64.encodeToString
org.apache.shiro.codec.Base64.encode
org.apache.shiro.codec.Base64.encode
org.apache.shiro.codec.CodecSupport.toString
org.apache.shiro.codec.CodecSupport.toString
com.anarsoft.agent.regression.MultiThreadedOneInstanceTemplate.run
    read  from field  com.anarsoft.agent.regression.MultiThreadedOneInstanceTemplate.threadCount from object 1461149300

Thus, there are only reads from the fields created when the DefaultPasswordService was created. In my test, creation happens in the main thread.

+1
source

, . :

public String encryptPassword(Object plaintext) {
  Hash hash = hashPassword(plaintext);
  checkHashFormatDurability();
  return this.hashFormat.format(hash);
}

, , , checkHashFormatDurability , encryptPassword , .

, , DefaultPasswordService , , . .

+2

, .

Technically, you need to make sure there are no calls setHashServiceor setHashFormatat run time encryptPassword(...). For example, a call setHashService(null)will result in encryptPassword(...)NPE raising.

In practice, this is probably not a problem, since it is unlikely that there will be a reason for changing the HashService or HashFormat after the service is started and started.

+1
source

Source: https://habr.com/ru/post/1584367/


All Articles