geosolutions-it / geobatch

Open Source GeoSpatial Processing Simplified
GNU General Public License v3.0
22 stars 19 forks source link

[Publish Actions] we should be able to encrypt passwords #25

Open ccancellieri opened 12 years ago

ccancellieri commented 12 years ago

In Publish actions:

etj commented 12 years ago

In some GB actions there is the need to connect to authenticated services, such as GeoServer or GeoNetwork. This means that some sensible information, such as login credentials, may appear in the configuration files. That said, it’s clear the need of not sharing these sensible information together with the GeoBatch flow configuration.

Approach limits

We need a way to have these information in the configuration files, yet encoded someway. We can’t encode them with a non-reversible algorithm (hashing and similar), because the used authentication mechanisms require that the client (i.e. GeoBatch) knows the credentials; It means that, using a set of encrypted information already in the server, GeoBatch should be able to compute the unencrypted credentials. As a logical consequence, the credentials cannot be completely hidden in the server, so there is no point in using strong cyphering algorithms to encode the credentials.

Proposal

The idea is to have a mechanism that allows a simple encoding of any sensible data, with the GB logic that performs all the steps to recover internally the hidden data, so that this mechanism can be applied to any action without changing any logic in the involved actions.

In the xml configuration of the single action, we may have a set of information which allow GeoBatch to rebuild the sensible data. We will have a string with the encoded value, and a string telling which is the field where the decoded string shall be saved into: e.g.: <encrypt value="HIDDEN_KEY" target="TARGET_FIELD"/> The BaseAction c’tor will process the encrypted field and will inject the decrypted data into the target field. It means that we may have multiple fields encoded that way.

<ActionXXX>
  <id>action_id</id>
  <name>Action Name</name>

  <encrypt value="HIDDEN_KEY" target="userName"/>
  <encrypt value="HIDDEN_KEY" target="password"/>

  <userName>dummy - will be overwritten </userName>
  <password>dummy - will be overwritten </password>

Other requirements

Since we don’t want in two different sites that identical decoded values will map in the same encoded value, we may have some a site-dependent “salt” that will alter the encoding in some way. We may have a value in the global settings that alter a bit the de/coding process, in order to have (unportable) site-specific encoded values.

As an optional requirement, we may want to be able to plug different encoding engines at deploy time. We can have a standard de/coder interface, and different implementation may be injected in the Action configuration resolver using Spring. How to encode data The system may decode data automatically, but how shall the admin compute the encoded values to put in the configuration files? A page may be added in the GeoBatch UI that, asking for the fixed “salt” value and the string to be encoded, would return the encoded value. A command-line version of this utility may be implemented as well.

etj commented 12 years ago
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

/**
 * 
 * @author ETj <etj at geo-solutions.it>
 */
public class PwEncoder {

    // 123456789 123456789 123456789 12
    private static final byte[] KEY = "installation dependant key needed".substring(0, 16)
            .getBytes();

    public static String encode(String msg) {
        try {
            SecretKeySpec keySpec = new SecretKeySpec(KEY, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);

            byte[] input = msg.getBytes();
            byte[] encrypted = cipher.doFinal(input);
            byte[] output = Base64.encodeBase64(encrypted);
            return new String(output);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException("Error while encoding", ex);
        } catch (NoSuchPaddingException ex) {
            throw new RuntimeException("Error while encoding", ex);
        } catch (IllegalBlockSizeException ex) {
            throw new RuntimeException("Error while encoding", ex);
        } catch (BadPaddingException ex) {
            throw new RuntimeException("Error while encoding", ex);
        } catch (InvalidKeyException ex) {
            throw new RuntimeException("Error while encoding", ex);
        }
    }

    public static String decode(String msg) {
        try {
            SecretKeySpec keySpec = new SecretKeySpec(KEY, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, keySpec);

            byte[] de64 = Base64.decodeBase64(msg);
            byte[] decrypted = cipher.doFinal(de64);

            return new String(decrypted);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException("Error while encoding", ex);
        } catch (NoSuchPaddingException ex) {
            throw new RuntimeException("Error while encoding", ex);
        } catch (IllegalBlockSizeException ex) {
            throw new RuntimeException("Error while encoding", ex);
        } catch (BadPaddingException ex) {
            throw new RuntimeException("Error while encoding", ex);
        } catch (InvalidKeyException ex) {
            throw new RuntimeException("Error while encoding", ex);
        }
    }
}
simboss commented 11 years ago

Let's transform this into a proposal and then move on.

etj commented 11 years ago

https://github.com/geosolutions-it/geobatch/wiki/Proposal-%237:-Encrypt-sensitive-data-in-configuration-files