You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-user@db.apache.org by Andrew Lawrenson <an...@coppereye.com> on 2008/09/29 15:30:16 UTC

Derby Encryption AND Replication

Hi All,

    is it possible to use replication to replicate an encrypted database.  Various things hint that it isn't supported (such as the StartSlave attribute not specifying that you can combine it with encryptionKey), but I can't find anything explicitly saying it isn't supported.

    If I boot the slave database without the encryption key, I get an exception with SQLState XBM06, as expected.  If I pass in the encryption details as well, so my connection attributes contains the following: "startSlave=true;slaveHost=192.168.0.211;slavePort=6959;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=aaaaaaaabbbbbbbb" then derby hangs indefinately whilst booting:

   java.lang.Thread.sleep(Native Method)
   org.apache.derby.impl.db.SlaveDatabase.verifySuccessfulBoot(Unknown Source)
   org.apache.derby.impl.db.SlaveDatabase.boot(Unknown Source)
   org.apache.derby.impl.services.monitor.BaseMonitor.boot(Unknown Source)
   org.apache.derby.impl.services.monitor.TopService.bootModule(Unknown Source)
   org.apache.derby.impl.services.monitor.BaseMonitor.bootService(Unknown Source)
   org.apache.derby.impl.services.monitor.BaseMonitor.startProviderService(Unknown Source)
   org.apache.derby.impl.services.monitor.BaseMonitor.findProviderAndStartService(Unknown Source)
   org.apache.derby.impl.services.monitor.BaseMonitor.startPersistentService(Unknown Source)
   org.apache.derby.iapi.services.monitor.Monitor.startPersistentService(Unknown Source)
   org.apache.derby.impl.jdbc.EmbedConnection.bootDatabase(Unknown Source)
   org.apache.derby.impl.jdbc.EmbedConnection.<init>(Unknown Source)
   org.apache.derby.impl.jdbc.EmbedConnection30.<init>(Unknown Source)
   org.apache.derby.impl.jdbc.EmbedConnection40.<init>(Unknown Source)
   org.apache.derby.jdbc.Driver40.getNewEmbedConnection(Unknown Source)
   org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
   org.apache.derby.jdbc.AutoloadedDriver.connect(Unknown Source)
   java.sql.DriverManager.getConnection(DriverManager.java:582)
   java.sql.DriverManager.getConnection(DriverManager.java:185)

Is it possible for anyone to confirm if this should be supported or not?

many thanks,

  Andrew Lawrenson

Re: Derby Encryption AND Replication

Posted by Jørgen Løland <Jo...@Sun.COM>.
Andrew Lawrenson wrote:
> Ok, I understand - many thanks!
> 
>         Andy
> 
> -----Original Message-----
> From: Jorgen.Loland@Sun.COM [mailto:Jorgen.Loland@Sun.COM]
> Sent: 30 September 2008 15:50
> To: Derby Discussion
> Subject: Re: Derby Encryption AND Replication
> 
> Andrew,
> 
> Right, this kind of problem (the NPE) is a good example of things that would need to be fixed. As I said, encryption/backup hasn't been tested together and can only be considered experimental functionality at this stage.
> 
> Regarding the question: Yes, it makes sense to me why startSlave has to be called before recover. Replication is based on not letting the slave leave recovery while replication is running. I.e, the slave is constantly doing recovery of the log records received from the master.
> The startSlave method does some initialization work that is needed before log can be received from the master.
> 
> That being said, the NPE problem can be fixed by setting the rawStoreFactory variable in LTF before parsing the log files (the second while loop in LTF#initializeReplicationSlaveRole). I tested this by writing a little hack: SlaveController#startSlave already knows about rawStore, so I just passed it to LTF#initializeReplicationSlaveMode and set it there. That removed the NPE. I created a bug report for this issue:
> 
> https://issues.apache.org/jira/browse/DERBY-3890
> 
> You are more than welcome to create a patch for it if you think the suggested solution is sound. However, I think maybe the LTF#rawStoreFactory should be initialized somewhere else than through SlaveController.

Hi Andrew,

A patch for this problem has been committed to the repository. It will 
be part of the next Derby release. If you don't want to wait, you can 
also try it out by downloading the source code from the repository.

-- 
Jørgen Løland

RE: Derby Encryption AND Replication

Posted by Andrew Lawrenson <an...@coppereye.com>.
Ok, I understand - many thanks!

        Andy

-----Original Message-----
From: Jorgen.Loland@Sun.COM [mailto:Jorgen.Loland@Sun.COM]
Sent: 30 September 2008 15:50
To: Derby Discussion
Subject: Re: Derby Encryption AND Replication

Andrew,

Right, this kind of problem (the NPE) is a good example of things that would need to be fixed. As I said, encryption/backup hasn't been tested together and can only be considered experimental functionality at this stage.

Regarding the question: Yes, it makes sense to me why startSlave has to be called before recover. Replication is based on not letting the slave leave recovery while replication is running. I.e, the slave is constantly doing recovery of the log records received from the master.
The startSlave method does some initialization work that is needed before log can be received from the master.

That being said, the NPE problem can be fixed by setting the rawStoreFactory variable in LTF before parsing the log files (the second while loop in LTF#initializeReplicationSlaveRole). I tested this by writing a little hack: SlaveController#startSlave already knows about rawStore, so I just passed it to LTF#initializeReplicationSlaveMode and set it there. That removed the NPE. I created a bug report for this issue:

https://issues.apache.org/jira/browse/DERBY-3890

You are more than welcome to create a patch for it if you think the suggested solution is sound. However, I think maybe the LTF#rawStoreFactory should be initialized somewhere else than through SlaveController.

Regards,
Jørgen Løland

Andrew Lawrenson wrote:
> Jorgen,
>
>         I've possibly found where the problem is being caused.  (This
> is with v 10.4.2.0)
>
> When booting my slave database, a nullpointer exception is being thrown whilst trying to decrypt data:
>
> Exception in thread "derby.slave.boot-DRS-H3G" java.lang.NullPointerException
>         at org.apache.derby.impl.store.raw.log.LogToFile.decrypt(LogToFile.java:4327)
>         at org.apache.derby.impl.store.raw.log.Scan.getNextRecordForward(Scan.java:844)
>         at org.apache.derby.impl.store.raw.log.Scan.getNextRecord(Scan.java:206)
>         at org.apache.derby.impl.store.raw.log.LogToFile.initializeReplicationSlaveRole(LogToFile.java:5228)
>         at org.apache.derby.impl.store.replication.slave.SlaveController.startSlave(SlaveController.java:232)
>         at org.apache.derby.impl.store.raw.RawStore.boot(RawStore.java:328)
>         at org.apache.derby.impl.services.monitor.BaseMonitor.boot(BaseMonitor.java:2019)
>         at org.apache.derby.impl.services.monitor.TopService.bootModule(TopService.java:291)
>         at org.apache.derby.impl.services.monitor.BaseMonitor.startModule(BaseMonitor.java:573)
>         at org.apache.derby.iapi.services.monitor.Monitor.bootServiceModule(Monitor.java:427)
>         at org.apache.derby.impl.store.access.RAMAccessManager.boot(RAMAccessManager.java:1019)
>         at org.apache.derby.impl.services.monitor.BaseMonitor.boot(BaseMonitor.java:2019)
>         at org.apache.derby.impl.services.monitor.TopService.bootModule(TopService.java:291)
>         at org.apache.derby.impl.services.monitor.BaseMonitor.startModule(BaseMonitor.java:573)
>         at org.apache.derby.iapi.services.monitor.Monitor.bootServiceModule(Monitor.java:427)
>         at org.apache.derby.impl.db.BasicDatabase.bootStore(BasicDatabase.java:780)
>         at org.apache.derby.impl.db.BasicDatabase.boot(BasicDatabase.java:196)
>         at org.apache.derby.impl.db.SlaveDatabase.bootBasicDatabase(SlaveDatabase.java:424)
>         at org.apache.derby.impl.db.SlaveDatabase.access$000(SlaveDatabase.java:70)
>         at org.apache.derby.impl.db.SlaveDatabase$SlaveDatabaseBootThread.run(SlaveDatabase.java:311)
>         at java.lang.Thread.run(Thread.java:619)
>
> As I see it, when you call SlaveController.startSlave(), you pass in a LogFactory object (which is actually a LogToFile object).
> This LogToFile object needs its "rawStoreFactory" object set before it can call decrypt() which is called as above - and this rawStoreFactory object is only set during a call to LogToFile.recover().
>
> However, in RawStore.boot(), where the LogFactory is created, LogFactory.recover() is only called _after_ SlaveController.startSlave():
>
>       // If SlaveFactory is to be booted, the boot has to happen
>       // before logFactory.recover since that method will be blocked
>       // when in replication slave mode.
>         if (inReplicationSlaveMode) {
>             // The LogFactory has already been booted in slave mode.
>             // Can now start slave replication by booting the
>             // SlaveFactory service
>             slaveFactory = (SlaveFactory)
>                 Monitor.bootServiceModule(create, this,
>                                           getSlaveFactoryModule(),
>                                           properties);
>         slaveFactory.startSlave(this, logFactory);
>       }
>
>         // no need to tell log factory which raw store factory it belongs to
>         // since this is passed into the log factory for recovery
>         // after the factories are loaded, recover the database
>         logFactory.recover(this, dataFactory, xactFactory);
>
> The comments here imply the order has to be this way round - however, it seems to be this ordering which is causing the problem in my case.
>
> At this point, I'm starting to feel quite out of my depth - does this make sense to you?

Re: Derby Encryption AND Replication

Posted by Jørgen Løland <Jo...@Sun.COM>.
Andrew,

Right, this kind of problem (the NPE) is a good example of things that 
would need to be fixed. As I said, encryption/backup hasn't been tested 
together and can only be considered experimental functionality at this 
stage.

Regarding the question: Yes, it makes sense to me why startSlave has to 
be called before recover. Replication is based on not letting the slave 
leave recovery while replication is running. I.e, the slave is 
constantly doing recovery of the log records received from the master. 
The startSlave method does some initialization work that is needed 
before log can be received from the master.

That being said, the NPE problem can be fixed by setting the 
rawStoreFactory variable in LTF before parsing the log files (the second 
while loop in LTF#initializeReplicationSlaveRole). I tested this by 
writing a little hack: SlaveController#startSlave already knows about 
rawStore, so I just passed it to LTF#initializeReplicationSlaveMode and 
set it there. That removed the NPE. I created a bug report for this issue:

https://issues.apache.org/jira/browse/DERBY-3890

You are more than welcome to create a patch for it if you think the 
suggested solution is sound. However, I think maybe the 
LTF#rawStoreFactory should be initialized somewhere else than through 
SlaveController.

Regards,
Jørgen Løland

Andrew Lawrenson wrote:
> Jorgen,
> 
>         I've possibly found where the problem is being caused.  (This is with v 10.4.2.0)
> 
> When booting my slave database, a nullpointer exception is being thrown whilst trying to decrypt data:
> 
> Exception in thread "derby.slave.boot-DRS-H3G" java.lang.NullPointerException
>         at org.apache.derby.impl.store.raw.log.LogToFile.decrypt(LogToFile.java:4327)
>         at org.apache.derby.impl.store.raw.log.Scan.getNextRecordForward(Scan.java:844)
>         at org.apache.derby.impl.store.raw.log.Scan.getNextRecord(Scan.java:206)
>         at org.apache.derby.impl.store.raw.log.LogToFile.initializeReplicationSlaveRole(LogToFile.java:5228)
>         at org.apache.derby.impl.store.replication.slave.SlaveController.startSlave(SlaveController.java:232)
>         at org.apache.derby.impl.store.raw.RawStore.boot(RawStore.java:328)
>         at org.apache.derby.impl.services.monitor.BaseMonitor.boot(BaseMonitor.java:2019)
>         at org.apache.derby.impl.services.monitor.TopService.bootModule(TopService.java:291)
>         at org.apache.derby.impl.services.monitor.BaseMonitor.startModule(BaseMonitor.java:573)
>         at org.apache.derby.iapi.services.monitor.Monitor.bootServiceModule(Monitor.java:427)
>         at org.apache.derby.impl.store.access.RAMAccessManager.boot(RAMAccessManager.java:1019)
>         at org.apache.derby.impl.services.monitor.BaseMonitor.boot(BaseMonitor.java:2019)
>         at org.apache.derby.impl.services.monitor.TopService.bootModule(TopService.java:291)
>         at org.apache.derby.impl.services.monitor.BaseMonitor.startModule(BaseMonitor.java:573)
>         at org.apache.derby.iapi.services.monitor.Monitor.bootServiceModule(Monitor.java:427)
>         at org.apache.derby.impl.db.BasicDatabase.bootStore(BasicDatabase.java:780)
>         at org.apache.derby.impl.db.BasicDatabase.boot(BasicDatabase.java:196)
>         at org.apache.derby.impl.db.SlaveDatabase.bootBasicDatabase(SlaveDatabase.java:424)
>         at org.apache.derby.impl.db.SlaveDatabase.access$000(SlaveDatabase.java:70)
>         at org.apache.derby.impl.db.SlaveDatabase$SlaveDatabaseBootThread.run(SlaveDatabase.java:311)
>         at java.lang.Thread.run(Thread.java:619)
> 
> As I see it, when you call SlaveController.startSlave(), you pass in a LogFactory object (which is actually a LogToFile object).
> This LogToFile object needs its "rawStoreFactory" object set before it can call decrypt() which is called as above - and this rawStoreFactory object is only set during a call to LogToFile.recover().
> 
> However, in RawStore.boot(), where the LogFactory is created, LogFactory.recover() is only called _after_ SlaveController.startSlave():
> 
>       // If SlaveFactory is to be booted, the boot has to happen
>       // before logFactory.recover since that method will be blocked
>       // when in replication slave mode.
>         if (inReplicationSlaveMode) {
>             // The LogFactory has already been booted in slave mode.
>             // Can now start slave replication by booting the
>             // SlaveFactory service
>             slaveFactory = (SlaveFactory)
>                 Monitor.bootServiceModule(create, this,
>                                           getSlaveFactoryModule(),
>                                           properties);
>         slaveFactory.startSlave(this, logFactory);
>       }
> 
>         // no need to tell log factory which raw store factory it belongs to
>         // since this is passed into the log factory for recovery
>         // after the factories are loaded, recover the database
>         logFactory.recover(this, dataFactory, xactFactory);
> 
> The comments here imply the order has to be this way round - however, it seems to be this ordering which is causing the problem in my case.
> 
> At this point, I'm starting to feel quite out of my depth - does this make sense to you?

RE: Derby Encryption AND Replication

Posted by Andrew Lawrenson <an...@coppereye.com>.
Jorgen,

        I've possibly found where the problem is being caused.  (This is with v 10.4.2.0)

When booting my slave database, a nullpointer exception is being thrown whilst trying to decrypt data:

Exception in thread "derby.slave.boot-DRS-H3G" java.lang.NullPointerException
        at org.apache.derby.impl.store.raw.log.LogToFile.decrypt(LogToFile.java:4327)
        at org.apache.derby.impl.store.raw.log.Scan.getNextRecordForward(Scan.java:844)
        at org.apache.derby.impl.store.raw.log.Scan.getNextRecord(Scan.java:206)
        at org.apache.derby.impl.store.raw.log.LogToFile.initializeReplicationSlaveRole(LogToFile.java:5228)
        at org.apache.derby.impl.store.replication.slave.SlaveController.startSlave(SlaveController.java:232)
        at org.apache.derby.impl.store.raw.RawStore.boot(RawStore.java:328)
        at org.apache.derby.impl.services.monitor.BaseMonitor.boot(BaseMonitor.java:2019)
        at org.apache.derby.impl.services.monitor.TopService.bootModule(TopService.java:291)
        at org.apache.derby.impl.services.monitor.BaseMonitor.startModule(BaseMonitor.java:573)
        at org.apache.derby.iapi.services.monitor.Monitor.bootServiceModule(Monitor.java:427)
        at org.apache.derby.impl.store.access.RAMAccessManager.boot(RAMAccessManager.java:1019)
        at org.apache.derby.impl.services.monitor.BaseMonitor.boot(BaseMonitor.java:2019)
        at org.apache.derby.impl.services.monitor.TopService.bootModule(TopService.java:291)
        at org.apache.derby.impl.services.monitor.BaseMonitor.startModule(BaseMonitor.java:573)
        at org.apache.derby.iapi.services.monitor.Monitor.bootServiceModule(Monitor.java:427)
        at org.apache.derby.impl.db.BasicDatabase.bootStore(BasicDatabase.java:780)
        at org.apache.derby.impl.db.BasicDatabase.boot(BasicDatabase.java:196)
        at org.apache.derby.impl.db.SlaveDatabase.bootBasicDatabase(SlaveDatabase.java:424)
        at org.apache.derby.impl.db.SlaveDatabase.access$000(SlaveDatabase.java:70)
        at org.apache.derby.impl.db.SlaveDatabase$SlaveDatabaseBootThread.run(SlaveDatabase.java:311)
        at java.lang.Thread.run(Thread.java:619)

As I see it, when you call SlaveController.startSlave(), you pass in a LogFactory object (which is actually a LogToFile object).
This LogToFile object needs its "rawStoreFactory" object set before it can call decrypt() which is called as above - and this rawStoreFactory object is only set during a call to LogToFile.recover().

However, in RawStore.boot(), where the LogFactory is created, LogFactory.recover() is only called _after_ SlaveController.startSlave():

      // If SlaveFactory is to be booted, the boot has to happen
      // before logFactory.recover since that method will be blocked
      // when in replication slave mode.
        if (inReplicationSlaveMode) {
            // The LogFactory has already been booted in slave mode.
            // Can now start slave replication by booting the
            // SlaveFactory service
            slaveFactory = (SlaveFactory)
                Monitor.bootServiceModule(create, this,
                                          getSlaveFactoryModule(),
                                          properties);
        slaveFactory.startSlave(this, logFactory);
      }

        // no need to tell log factory which raw store factory it belongs to
        // since this is passed into the log factory for recovery
        // after the factories are loaded, recover the database
        logFactory.recover(this, dataFactory, xactFactory);

The comments here imply the order has to be this way round - however, it seems to be this ordering which is causing the problem in my case.

At this point, I'm starting to feel quite out of my depth - does this make sense to you?

Thanks again,

        Andy




-----Original Message-----
From: Andrew Lawrenson [mailto:andrew.lawrenson@coppereye.com]
Sent: 30 September 2008 10:29
To: Derby Discussion
Subject: RE: Derby Encryption AND Replication

Jorgen,

        thanks for your clarification regarding the status of this combination of features.

        I think my issue is something more than just waiting for the master to connect, as:

1) once the slave gets in it's "hanging" state, it is not listening on the slave port, as checked via netstat.

If I'm using a non-encrypted database, it works fine and is listening ok:
-bash-3.00$ netstat -a | grep 6959
myserver.6959              *.*                0      0 49152      0 LISTEN

2) when the master tries to connect to it, it gets a connection refused:

Caused by: ERROR XRE04: Could not establish a connection to the peer of the replicated database 'DRS-H3G' on address 'myserver.boxhouse.indigo-one.com:6959'.
        at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
        at org.apache.derby.impl.store.replication.master.MasterController.setupConnection(Unknown Source)
        at org.apache.derby.impl.store.replication.master.MasterController.startMaster(Unknown Source)
        at org.apache.derby.impl.store.raw.RawStore.startReplicationMaster(Unknown Source)
        at org.apache.derby.impl.store.access.RAMAccessManager.startReplicationMaster(Unknown Source)
        ... 16 more
Caused by: java.security.PrivilegedActionException: java.net.ConnectException: Connection refused
        at java.security.AccessController.doPrivileged(Native Method)
        at org.apache.derby.impl.store.replication.net.ReplicationMessageTransmit.initConnection(Unknown Source)
        ... 20 more
Caused by: java.net.ConnectException: Connection refused
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
        at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
        at java.net.Socket.connect(Socket.java:519)
        at org.apache.derby.impl.store.replication.net.ReplicationMessageTransmit$1.run(Unknown Source)
        ... 22 more

Whereas this works fine with a non-encrypted database.

I'll continue digging, and try to find out what is going on...

Thanks again,

        Andy

-----Original Message-----
From: Jorgen.Loland@Sun.COM [mailto:Jorgen.Loland@Sun.COM]
Sent: 30 September 2008 10:01
To: Derby Discussion
Subject: Re: Derby Encryption AND Replication

Hi Andrew,

The reason why encryption and replication is not documented is because it has not been tested at all. Theoretically, there is nothing I can think of that will prevent it from working [1]. On the other hand, we may have forgotten some details that I expect to be easy fixes if somebody volunteers.

The hang you get on the slave is expected. When you boot a database in slave mode, the connection attempt is designed to hang until the master connects to it. For details, take a look at this page in the Derby Server and Admin guide:

http://db.apache.org/derby/docs/10.4/adminguide/cadminreplication.html

I have created an encrypted database and tried the connection string you suggested [2]. I successfully set up replication, and did some simple DML and DDL operations on the master. The operations were correctly reflected on the slave after failover, as expected.

Thus:
* It does work in theory
* A simple test confirmed that it works
* This combination of features has not been tested thoroughly.
* We may have forgotten some corner cases that needs to be fixed

Conclusion:
* I can not guarantee correct results, although I am pretty sure it will work.


[1] Replication works by sending the (recovery) log records from the master to the slave. The log records store physical changes to disk blocks, and in encrypted mode these changes are encrypted as well.
Replication has a lot in common with Derby's Online Backup feature which
*does* support encryption.

[2]
1. Master: connect
'jdbc:derby:enctest2;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test;create=true';
2. Master:  CALL SYSCS_UTIL.SYSCS_FREEZE_DATABASE();
3. Slave: connect
'jdbc:derby:enctest2;startSlave=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
4. Master: connect
'jdbc:derby:enctest2;startMaster=true;slaveHost=localhost;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
5. Master: do some test DDL and DML operations
6: Master: connect 'jdbc:derby:enctest2;failover=true';
7: Slave: connect
'jdbc:derby:enctest2;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
8. Slave: ensure results are as expected

Hope this helps,
Jørgen Løland

Andrew Lawrenson wrote:
> Hi All,
>
>     is it possible to use replication to replicate an encrypted database.  Various things hint that it isn't supported (such as the StartSlave attribute not specifying that you can combine it with encryptionKey), but I can't find anything explicitly saying it isn't supported.
>
>     If I boot the slave database without the encryption key, I get an exception with SQLState XBM06, as expected.  If I pass in the encryption details as well, so my connection attributes contains the following: "startSlave=true;slaveHost=192.168.0.211;slavePort=6959;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=aaaaaaaabbbbbbbb" then derby hangs indefinately whilst booting:
>
>    java.lang.Thread.sleep(Native Method)
>    org.apache.derby.impl.db.SlaveDatabase.verifySuccessfulBoot(Unknown Source)
>    org.apache.derby.impl.db.SlaveDatabase.boot(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.boot(Unknown Source)
>    org.apache.derby.impl.services.monitor.TopService.bootModule(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.bootService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.startProviderService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.findProviderAndStartService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.startPersistentService(Unknown Source)
>    org.apache.derby.iapi.services.monitor.Monitor.startPersistentService(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection.bootDatabase(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection.<init>(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection30.<init>(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection40.<init>(Unknown Source)
>    org.apache.derby.jdbc.Driver40.getNewEmbedConnection(Unknown Source)
>    org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
>    org.apache.derby.jdbc.AutoloadedDriver.connect(Unknown Source)
>    java.sql.DriverManager.getConnection(DriverManager.java:582)
>    java.sql.DriverManager.getConnection(DriverManager.java:185)
>
> Is it possible for anyone to confirm if this should be supported or not?
>
> many thanks,
>
>   Andrew Lawrenson
>

RE: Derby Encryption AND Replication

Posted by Andrew Lawrenson <an...@coppereye.com>.
Jorgen,

        thanks for your clarification regarding the status of this combination of features.

        I think my issue is something more than just waiting for the master to connect, as:

1) once the slave gets in it's "hanging" state, it is not listening on the slave port, as checked via netstat.

If I'm using a non-encrypted database, it works fine and is listening ok:
-bash-3.00$ netstat -a | grep 6959
myserver.6959              *.*                0      0 49152      0 LISTEN

2) when the master tries to connect to it, it gets a connection refused:

Caused by: ERROR XRE04: Could not establish a connection to the peer of the replicated database 'DRS-H3G' on address 'myserver.boxhouse.indigo-one.com:6959'.
        at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
        at org.apache.derby.impl.store.replication.master.MasterController.setupConnection(Unknown Source)
        at org.apache.derby.impl.store.replication.master.MasterController.startMaster(Unknown Source)
        at org.apache.derby.impl.store.raw.RawStore.startReplicationMaster(Unknown Source)
        at org.apache.derby.impl.store.access.RAMAccessManager.startReplicationMaster(Unknown Source)
        ... 16 more
Caused by: java.security.PrivilegedActionException: java.net.ConnectException: Connection refused
        at java.security.AccessController.doPrivileged(Native Method)
        at org.apache.derby.impl.store.replication.net.ReplicationMessageTransmit.initConnection(Unknown Source)
        ... 20 more
Caused by: java.net.ConnectException: Connection refused
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
        at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
        at java.net.Socket.connect(Socket.java:519)
        at org.apache.derby.impl.store.replication.net.ReplicationMessageTransmit$1.run(Unknown Source)
        ... 22 more

Whereas this works fine with a non-encrypted database.

I'll continue digging, and try to find out what is going on...

Thanks again,

        Andy

-----Original Message-----
From: Jorgen.Loland@Sun.COM [mailto:Jorgen.Loland@Sun.COM]
Sent: 30 September 2008 10:01
To: Derby Discussion
Subject: Re: Derby Encryption AND Replication

Hi Andrew,

The reason why encryption and replication is not documented is because it has not been tested at all. Theoretically, there is nothing I can think of that will prevent it from working [1]. On the other hand, we may have forgotten some details that I expect to be easy fixes if somebody volunteers.

The hang you get on the slave is expected. When you boot a database in slave mode, the connection attempt is designed to hang until the master connects to it. For details, take a look at this page in the Derby Server and Admin guide:

http://db.apache.org/derby/docs/10.4/adminguide/cadminreplication.html

I have created an encrypted database and tried the connection string you suggested [2]. I successfully set up replication, and did some simple DML and DDL operations on the master. The operations were correctly reflected on the slave after failover, as expected.

Thus:
* It does work in theory
* A simple test confirmed that it works
* This combination of features has not been tested thoroughly.
* We may have forgotten some corner cases that needs to be fixed

Conclusion:
* I can not guarantee correct results, although I am pretty sure it will work.


[1] Replication works by sending the (recovery) log records from the master to the slave. The log records store physical changes to disk blocks, and in encrypted mode these changes are encrypted as well.
Replication has a lot in common with Derby's Online Backup feature which
*does* support encryption.

[2]
1. Master: connect
'jdbc:derby:enctest2;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test;create=true';
2. Master:  CALL SYSCS_UTIL.SYSCS_FREEZE_DATABASE();
3. Slave: connect
'jdbc:derby:enctest2;startSlave=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
4. Master: connect
'jdbc:derby:enctest2;startMaster=true;slaveHost=localhost;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
5. Master: do some test DDL and DML operations
6: Master: connect 'jdbc:derby:enctest2;failover=true';
7: Slave: connect
'jdbc:derby:enctest2;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
8. Slave: ensure results are as expected

Hope this helps,
Jørgen Løland

Andrew Lawrenson wrote:
> Hi All,
>
>     is it possible to use replication to replicate an encrypted database.  Various things hint that it isn't supported (such as the StartSlave attribute not specifying that you can combine it with encryptionKey), but I can't find anything explicitly saying it isn't supported.
>
>     If I boot the slave database without the encryption key, I get an exception with SQLState XBM06, as expected.  If I pass in the encryption details as well, so my connection attributes contains the following: "startSlave=true;slaveHost=192.168.0.211;slavePort=6959;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=aaaaaaaabbbbbbbb" then derby hangs indefinately whilst booting:
>
>    java.lang.Thread.sleep(Native Method)
>    org.apache.derby.impl.db.SlaveDatabase.verifySuccessfulBoot(Unknown Source)
>    org.apache.derby.impl.db.SlaveDatabase.boot(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.boot(Unknown Source)
>    org.apache.derby.impl.services.monitor.TopService.bootModule(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.bootService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.startProviderService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.findProviderAndStartService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.startPersistentService(Unknown Source)
>    org.apache.derby.iapi.services.monitor.Monitor.startPersistentService(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection.bootDatabase(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection.<init>(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection30.<init>(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection40.<init>(Unknown Source)
>    org.apache.derby.jdbc.Driver40.getNewEmbedConnection(Unknown Source)
>    org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
>    org.apache.derby.jdbc.AutoloadedDriver.connect(Unknown Source)
>    java.sql.DriverManager.getConnection(DriverManager.java:582)
>    java.sql.DriverManager.getConnection(DriverManager.java:185)
>
> Is it possible for anyone to confirm if this should be supported or not?
>
> many thanks,
>
>   Andrew Lawrenson
>

Re: Derby Encryption AND Replication

Posted by Jørgen Løland <Jo...@Sun.COM>.
Hi Andrew,

The reason why encryption and replication is not documented is because 
it has not been tested at all. Theoretically, there is nothing I can 
think of that will prevent it from working [1]. On the other hand, we 
may have forgotten some details that I expect to be easy fixes if 
somebody volunteers.

The hang you get on the slave is expected. When you boot a database in 
slave mode, the connection attempt is designed to hang until the master 
connects to it. For details, take a look at this page in the Derby 
Server and Admin guide:

http://db.apache.org/derby/docs/10.4/adminguide/cadminreplication.html

I have created an encrypted database and tried the connection string you 
suggested [2]. I successfully set up replication, and did some simple 
DML and DDL operations on the master. The operations were correctly 
reflected on the slave after failover, as expected.

Thus:
* It does work in theory
* A simple test confirmed that it works
* This combination of features has not been tested thoroughly.
* We may have forgotten some corner cases that needs to be fixed

Conclusion:
* I can not guarantee correct results, although I am pretty sure it will 
work.


[1] Replication works by sending the (recovery) log records from the 
master to the slave. The log records store physical changes to disk 
blocks, and in encrypted mode these changes are encrypted as well. 
Replication has a lot in common with Derby's Online Backup feature which 
*does* support encryption.

[2]
1. Master: connect 
'jdbc:derby:enctest2;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test;create=true';
2. Master:  CALL SYSCS_UTIL.SYSCS_FREEZE_DATABASE();
3. Slave: connect 
'jdbc:derby:enctest2;startSlave=true;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
4. Master: connect 
'jdbc:derby:enctest2;startMaster=true;slaveHost=localhost;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
5. Master: do some test DDL and DML operations
6: Master: connect 'jdbc:derby:enctest2;failover=true';
7: Slave: connect 
'jdbc:derby:enctest2;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=test';
8. Slave: ensure results are as expected

Hope this helps,
Jørgen Løland

Andrew Lawrenson wrote:
> Hi All,
> 
>     is it possible to use replication to replicate an encrypted database.  Various things hint that it isn't supported (such as the StartSlave attribute not specifying that you can combine it with encryptionKey), but I can't find anything explicitly saying it isn't supported.
> 
>     If I boot the slave database without the encryption key, I get an exception with SQLState XBM06, as expected.  If I pass in the encryption details as well, so my connection attributes contains the following: "startSlave=true;slaveHost=192.168.0.211;slavePort=6959;encryptionAlgorithm=DES/CBC/NoPadding;encryptionKey=aaaaaaaabbbbbbbb" then derby hangs indefinately whilst booting:
> 
>    java.lang.Thread.sleep(Native Method)
>    org.apache.derby.impl.db.SlaveDatabase.verifySuccessfulBoot(Unknown Source)
>    org.apache.derby.impl.db.SlaveDatabase.boot(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.boot(Unknown Source)
>    org.apache.derby.impl.services.monitor.TopService.bootModule(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.bootService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.startProviderService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.findProviderAndStartService(Unknown Source)
>    org.apache.derby.impl.services.monitor.BaseMonitor.startPersistentService(Unknown Source)
>    org.apache.derby.iapi.services.monitor.Monitor.startPersistentService(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection.bootDatabase(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection.<init>(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection30.<init>(Unknown Source)
>    org.apache.derby.impl.jdbc.EmbedConnection40.<init>(Unknown Source)
>    org.apache.derby.jdbc.Driver40.getNewEmbedConnection(Unknown Source)
>    org.apache.derby.jdbc.InternalDriver.connect(Unknown Source)
>    org.apache.derby.jdbc.AutoloadedDriver.connect(Unknown Source)
>    java.sql.DriverManager.getConnection(DriverManager.java:582)
>    java.sql.DriverManager.getConnection(DriverManager.java:185)
> 
> Is it possible for anyone to confirm if this should be supported or not?
> 
> many thanks,
> 
>   Andrew Lawrenson
>