Package au.net.causal.projo.prefs.transform

Source Code of au.net.causal.projo.prefs.transform.EncryptedValueTransformer$DecryptGetChain

package au.net.causal.projo.prefs.transform;

import org.jasypt.encryption.ByteEncryptor;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;

import au.net.causal.projo.annotation.Secure;
import au.net.causal.projo.prefs.DataTypeSupport;
import au.net.causal.projo.prefs.PreferenceKeyMetadata;
import au.net.causal.projo.prefs.PreferencesException;
import au.net.causal.projo.prefs.TransformDataTypeSupportChain;
import au.net.causal.projo.prefs.TransformGetChain;
import au.net.causal.projo.prefs.TransformPutChain;
import au.net.causal.projo.prefs.TransformRemoveChain;
import au.net.causal.projo.prefs.TransformResult;
import au.net.causal.projo.prefs.UnsupportedDataTypeException;
import au.net.causal.projo.prefs.security.UserAbortedEnteringPasswordException;

/**
* Encrypts/decrypts any value whose key is annotated with {@literal @}{@link Secure}.  Any key marked with this annotation will be processed by this transformer
* regardless of this data type, even if the data type is not supported.  This may result in run time errors, but this is better than silently not encrypting
* certain keys.
* <p>
*
* The transformer will attempt to convert the data type to a byte array using other transformers first, then encrypt the data using the supplied encrypter,
* then store this encrypted data, also in byte array form, into the preference store, again using other transformers where needed for data type conversion
* if the store does not support byte arrays natively.
*
* @author prunge
*/
public class EncryptedValueTransformer implements PreferenceTransformer
{
  private final ByteEncryptor encrypter;
 
  /**
   * Creates an <code>EncryptedValueTransformer</code> that uses the specified encrypter.
   *
   * @param encrypter the encrypter that performs encryption and decryption of data.
   *
   * @throws NullPointerException if <code>encrypter</code> is null.
   */
  public EncryptedValueTransformer(ByteEncryptor encrypter)
  {
    if (encrypter == null)
      throw new NullPointerException("encrypter == null");
   
    this.encrypter = encrypter;
  }
 
  @Override
  public <T> TransformResult<T> applyGet(String key, PreferenceKeyMetadata<T> keyMetadata, TransformGetChain chain) throws PreferencesException
  {
    if (!isSecure(keyMetadata))
      return(null);
   
    return(new TransformResult<>(chain.getValueWithRestartedChain(key, keyMetadata.withoutAnnotationType(Secure.class), new DecryptGetChain(chain))));
  }

  @Override
  public <T> boolean applyPut(String key, T value, PreferenceKeyMetadata<T> keyMetadata, TransformPutChain chain) throws PreferencesException
  {
    if (!isSecure(keyMetadata))
      return(false);
   
    //Target is a byte array
    chain.putValueWithRestartedChain(key, value, keyMetadata.withoutAnnotationType(Secure.class), new EncryptPutChain(chain));
   
    return(true);
  }

  @Override
  public <T> boolean applyRemove(String key, PreferenceKeyMetadata<T> keyMetadata, TransformRemoveChain chain) throws PreferencesException
  {
    if (!isSecure(keyMetadata))
      return(false);
   
    //Target type will be byte array, always
    chain.removeValue(key, keyMetadata.withDataType(byte[].class).withoutAnnotationType(Secure.class));
   
    return(true);
   
  }

  @Override
  public DataTypeSupport applyDataTypeSupport(PreferenceKeyMetadata<?> keyMetadata, TransformDataTypeSupportChain chain) throws PreferencesException
  {
    //TODO actually this is affected?
   
    //Since we don't add any supported data types just ignore this
    return(null);
  }
 
  private boolean isSecure(PreferenceKeyMetadata<?> keyMetadata)
  {
    return(keyMetadata.isAnnotationPresent(Secure.class));
  }
 
  /**
   * Encrypts data using the encrypter, throwing appropriate preference exceptions where necessary.
   *
   * @param data the data to encrypt.  Must not be null.
   *
   * @return the encrypted data.
   *
   * @throws PreferencesException if the encryption fails or if user-interaction results in the process being cancelled.
   *
   * @see #decrypt(byte[])
   */
  protected byte[] encrypt(byte[] data)
  throws PreferencesException
  {
    try
    {
      return(encrypter.encrypt(data));
    }
    catch (EncryptionOperationNotPossibleException e)
    {
      throw new PreferencesException("Encryption failed: " + e, e);
    }
    catch (UserAbortedEnteringPasswordException e)
    {
      throw new PreferencesException("User aborted encryption.", e);
    }
  }
 
  /**
   * Decrypts data using the encrypter, throwing appropriate preference exceptions where necessary.
   *
   * @param data the data to decrypt.  Must not be null.
   *
   * @return the decrypted data.
   *
   * @throws PreferencesException if the encryption fails or if user-interaction results in the process being cancelled.
   *
   * @see #encrypt(byte[])
   */
  protected byte[] decrypt(byte[] data)
  throws PreferencesException
  {
    try
    {
      return(encrypter.decrypt(data));
    }
    catch (EncryptionOperationNotPossibleException e)
    {
      throw new PreferencesException("Decryption failed: " + e, e);
    }
    catch (UserAbortedEnteringPasswordException e)
    {
      throw new PreferencesException("User aborted decryption.", e);
    }
  }
 
  /**
   * Custom data type support chain that only supports <code>byte[]</code> data types.  Used to force the transformers to transform to this data type
   * where possible.
   *
   * @author prunge
   */
  private abstract class ChainWithDataTypeSupport implements TransformDataTypeSupportChain
  {
    @Override
    public boolean isDataTypeSupported(PreferenceKeyMetadata<?> keyMetadata) throws PreferencesException
    {
      if (byte[].class.equals(keyMetadata.getDataType().getRawType()))
        return(true);
      else
        return(false);
    }
   
    @Override
    public boolean isDataTypeSupportedNatively(PreferenceKeyMetadata<?> keyMetadata) throws PreferencesException
    {
      return(isDataTypeSupported(keyMetadata));
    }
   
    @Override
    public boolean isDataTypeSupportedNativelyWithRestartedChain(PreferenceKeyMetadata<?> keyMetadata, TransformDataTypeSupportChain newEndpoint)
        throws PreferencesException
    {
      return(isDataTypeSupported(keyMetadata));
    }
   
    @Override
    public boolean isDataTypeSupportedWithRestartedChain(PreferenceKeyMetadata<?> keyMetadata, TransformDataTypeSupportChain newEndpoint)
        throws PreferencesException
    {
      return(isDataTypeSupported(keyMetadata));
    }
  }
 
  /**
   * Get chain that performs decryption after reading from the original chain.
   *
   * @author prunge
   */
  private class DecryptGetChain extends ChainWithDataTypeSupport implements TransformGetChain
  {
    private final TransformGetChain originalChain;
   
    public DecryptGetChain(TransformGetChain originalChain)
    {
      this.originalChain = originalChain;
    }
   
    @Override
    public <T> T getValue(String key, PreferenceKeyMetadata<T> keyMetadata)
    throws UnsupportedDataTypeException, PreferencesException
    {
      //Read from original chain, decrypt the data
      byte[] encryptedData = originalChain.getValue(key, keyMetadata.withDataType(byte[].class).withoutAnnotationType(Secure.class));
      byte[] decryptedData = decrypt(encryptedData);
     
      //Will only ever be byte[]
      return((T)decryptedData);
    }
   
    @Override
    public <T> T getValueWithRestartedChain(String key, PreferenceKeyMetadata<T> keyMetadata, TransformGetChain newEndpoint)
    throws UnsupportedDataTypeException, PreferencesException
    {
      return(getValue(key, keyMetadata));
    }
  }
 
  /**
   * Put chain that performs encryption before storing using the original chain.
   * @author prunge
   *
   */
  private class EncryptPutChain extends ChainWithDataTypeSupport implements TransformPutChain
  {
    private final TransformPutChain originalChain;
   
    public EncryptPutChain(TransformPutChain originalChain)
    {
      this.originalChain = originalChain;
    }
   
    @Override
    public <T> void putValueWithRestartedChain(String key, T value, PreferenceKeyMetadata<T> keyMetadata, TransformPutChain newEndpoint)
    throws UnsupportedDataTypeException, PreferencesException
    {
      putValue(key, value, keyMetadata);
    }
   
    @Override
    public <T> void putValue(String key, T value, PreferenceKeyMetadata<T> keyMetadata) throws UnsupportedDataTypeException, PreferencesException
    {
      if (!byte[].class.equals(keyMetadata.getDataType().getRawType()))
        throw new UnsupportedDataTypeException(keyMetadata.getDataType());
     
      byte[] bValue = (byte[])value;
      bValue = encrypt(bValue);
     
      originalChain.putValue(key, bValue, keyMetadata.withDataType(byte[].class));
    }
  }
 
}
TOP

Related Classes of au.net.causal.projo.prefs.transform.EncryptedValueTransformer$DecryptGetChain

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.