package org.springframework.security.token;

import java.io.InputStream;
import java.security.SecureRandom;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;

/**
 * Creates a {@link SecureRandom} instance.
 * 
 * @author Ben Alex
 * @since 2.0.1
 *
 */
public class SecureRandomFactoryBean implements FactoryBean {

	private String algorithm = "SHA1PRNG";
	private Resource seed;
	
	public Object getObject() throws Exception {
		SecureRandom rnd = SecureRandom.getInstance(algorithm);
		
		if (seed != null) {
			// Seed specified, so use it
			byte[] seedBytes = FileCopyUtils.copyToByteArray(seed.getInputStream());
			rnd.setSeed(seedBytes);
		} else {
			// Request the next bytes, thus eagerly incurring the expense of default seeding
			rnd.nextBytes(new byte[1]);
		}
		
		return rnd;
	}

	public Class getObjectType() {
		return SecureRandom.class;
	}

	public boolean isSingleton() {
		return false;
	}

	/**
	 * Allows the Pseudo Random Number Generator (PRNG) algorithm to be nominated. Defaults to
	 * SHA1PRNG.
	 * 
	 * @param algorithm to use (mandatory)
	 */
	public void setAlgorithm(String algorithm) {
		Assert.hasText(algorithm, "Algorithm required");
		this.algorithm = algorithm;
	}

	/**
	 * Allows the user to specify a resource which will act as a seed for the {@link SecureRandom}
	 * instance. Specifically, the resource will be read into an {@link InputStream} and those
	 * bytes presented to the {@link SecureRandom#setSeed(byte[])} method. Note that this will
	 * simply supplement, rather than replace, the existing seed. As such, it is always safe to
	 * set a seed using this method (it never reduces randomness).
	 * 
	 * @param seed to use, or <code>null</code> if no additional seeding is needed
	 */
	public void setSeed(Resource seed) {
		this.seed = seed;
	}
}
