CloudSlang/cloud-slang

View on GitHub
cloudslang-entities/src/main/java/io/cloudslang/lang/entities/bindings/values/SensitiveValue.java

Summary

Maintainability
A
1 hr
Test Coverage
/*******************************************************************************
 * (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0 which accompany this distribution.
 *
 * The Apache License is available at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *******************************************************************************/
package io.cloudslang.lang.entities.bindings.values;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.cloudslang.lang.entities.SensitivityLevel;
import io.cloudslang.lang.entities.encryption.EncryptionProvider;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import io.cloudslang.lang.spi.encryption.Encryption;
import javassist.util.proxy.ProxyObjectInputStream;
import javassist.util.proxy.ProxyObjectOutputStream;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;

/**
 * Sensitive InOutParam value
 * <p>
 * Created by Ifat Gavish on 19/04/2016
 */
public class SensitiveValue implements Value {

    private static final long serialVersionUID = -1494652686913646816L;

    public static final String SENSITIVE_VALUE_MASK = "********";

    private String content = null;

    /**
     * This variable only used when passing sensitive data between application components which use
     * different encryption key
     * Json serialization in database should not deal with it
     */
    @JsonIgnore
    private Serializable originalContent = null;

    private SensitivityLevel sensitivityLevel = SensitivityLevel.ENCRYPTED;

    @SuppressWarnings("unused")
    protected SensitiveValue() {
    }

    protected SensitiveValue(Serializable content) {
        originalContent = content;
        encrypt();
    }

    protected SensitiveValue(Serializable content, SensitivityLevel sensitivityLevel) {
        this.sensitivityLevel = sensitivityLevel;
        originalContent = content;
        encrypt();
    }

    protected SensitiveValue(String content, boolean preEncrypted) {
        if (preEncrypted) {
            this.content = content;
        } else {
            originalContent = content;
            encrypt();
        }
    }

    public void encrypt() {
        if (originalContent != null) {
            content = encrypt(originalContent);
            originalContent = null;
        }
    }

    protected String encrypt(Serializable originalContent) {
        byte[] serialized = serialize(originalContent);
        String serializedAsString = Base64.encodeBase64String(serialized);
        Encryption encryption = EncryptionProvider.get();
        if (SensitivityLevel.OBFUSCATED == sensitivityLevel) {
            return encryption.obfuscate(serializedAsString);
        } else {
            return encryption.encrypt(serializedAsString.toCharArray());
        }
    }

    public void decrypt() {
        if (content != null) {
            originalContent = decrypt(content);
            content = null;
        }
    }

    protected Serializable decrypt(String content) {
        Encryption encryption = EncryptionProvider.get();
        char[] decrypted;
        if (SensitivityLevel.OBFUSCATED == sensitivityLevel) {
            decrypted = encryption.deobfuscate(content);
        } else {
            decrypted = encryption.decrypt(content);
        }
        String serializedAsString = new String(decrypted);

        byte[] serialized = Base64.decodeBase64(serializedAsString);
        return deserialize(serialized);
    }

    public String getContent() {
        return (content != null) ? content : ((originalContent != null) ? originalContent.toString() : null);
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Serializable getOriginalContent() {
        return originalContent;
    }

    public SensitivityLevel getSensitivityLevel() {
        return sensitivityLevel;
    }

    @Override
    public Serializable get() {
        return (originalContent != null) ? originalContent : ((content == null) ? null : decrypt(content));
    }

    @JsonIgnore
    @Override
    public boolean isSensitive() {
        return true;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        SensitiveValue that = (SensitiveValue) o;

        if (content != null ? !content.equals(that.content) : that.content != null) {
            return false;
        }
        return originalContent != null ? originalContent.equals(that.originalContent) : that.originalContent == null;

    }

    @Override
    public int hashCode() {
        int result = content != null ? content.hashCode() : 0;
        result = 31 * result + (originalContent != null ? originalContent.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return SENSITIVE_VALUE_MASK;
    }

    private byte[] serialize(Serializable data) {
        ObjectOutputStream oos = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            oos = new ProxyObjectOutputStream(baos);
            oos.writeObject(data);
            return baos.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to serialize object", e);
        } finally {
            if (oos != null) {
                IOUtils.closeQuietly(oos);
            }
        }
    }

    private Serializable deserialize(byte[] data) {
        ObjectInputStream ois = null;
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(data);
            ois = new ProxyObjectInputStream(bais);
            return (Serializable) ois.readObject();
        } catch (Exception e) {
            throw new RuntimeException("Failed to deserialize object", e);
        } finally {
            if (ois != null) {
                IOUtils.closeQuietly(ois);
            }
        }
    }
}