View Javadoc

1   /**
2      This file is part of GoldenGate Project (named also GoldenGate or GG).
3   
4      Copyright 2009, Frederic Bregier, and individual contributors by the @author
5      tags. See the COPYRIGHT.txt in the distribution for a full listing of
6      individual contributors.
7   
8      All GoldenGate Project is free software: you can redistribute it and/or 
9      modify it under the terms of the GNU General Public License as published 
10     by the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12  
13     GoldenGate is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17  
18     You should have received a copy of the GNU General Public License
19     along with GoldenGate .  If not, see <http://www.gnu.org/licenses/>.
20   */
21  package openr66.database.data;
22  
23  import goldengate.common.database.DbPreparedStatement;
24  import goldengate.common.database.DbSession;
25  import goldengate.common.database.data.AbstractDbData;
26  import goldengate.common.database.data.DbValue;
27  import goldengate.common.database.exception.GoldenGateDatabaseException;
28  import goldengate.common.database.exception.GoldenGateDatabaseNoConnectionException;
29  import goldengate.common.database.exception.GoldenGateDatabaseNoDataException;
30  import goldengate.common.database.exception.GoldenGateDatabaseSqlException;
31  import goldengate.common.digest.FilesystemBasedDigest;
32  import goldengate.common.utility.GgStringUtils;
33  
34  import java.net.InetSocketAddress;
35  import java.net.SocketAddress;
36  import java.sql.SQLException;
37  import java.sql.Types;
38  import java.util.ArrayList;
39  import java.util.concurrent.ConcurrentHashMap;
40  
41  import openr66.context.R66Session;
42  import openr66.protocol.configuration.Configuration;
43  import openr66.protocol.networkhandler.NetworkTransaction;
44  
45  /**
46   * Host Authentication Table object
47   *
48   * @author Frederic Bregier
49   *
50   */
51  public class DbHostAuth extends AbstractDbData {
52      public static enum Columns {
53          ADDRESS, PORT, ISSSL, HOSTKEY, ADMINROLE, ISCLIENT, UPDATEDINFO, HOSTID
54      }
55  
56      public static final int[] dbTypes = {
57          Types.VARCHAR, Types.INTEGER, Types.BIT,
58          Types.VARBINARY, Types.BIT, Types.BIT, Types.INTEGER, Types.VARCHAR };
59  
60      public static final String table = " HOSTS ";
61  
62      /**
63       * HashTable in case of lack of database
64       */
65      private static final ConcurrentHashMap<String, DbHostAuth> dbR66HostAuthHashMap =
66          new ConcurrentHashMap<String, DbHostAuth>();
67  
68      private String hostid;
69  
70      private String address;
71  
72      private int port;
73  
74      private boolean isSsl;
75  
76      private byte[] hostkey;
77  
78      private boolean adminrole;
79      
80      private boolean isClient;
81  
82      private int updatedInfo = UpdatedInfo.UNKNOWN.ordinal();
83  
84      // ALL TABLE SHOULD IMPLEMENT THIS
85      public static final int NBPRKEY = 1;
86  
87      protected static final String selectAllFields = Columns.ADDRESS.name() + "," +
88              Columns.PORT.name() + "," +Columns.ISSSL.name() + "," +
89              Columns.HOSTKEY.name() + "," +
90              Columns.ADMINROLE.name() + "," + Columns.ISCLIENT.name() + "," + 
91              Columns.UPDATEDINFO.name() + "," +
92              Columns.HOSTID.name();
93  
94      protected static final String updateAllFields =
95          Columns.ADDRESS.name() + "=?," +Columns.PORT.name() +
96          "=?," +Columns.ISSSL.name() + "=?," + Columns.HOSTKEY.name() +
97              "=?," + Columns.ADMINROLE.name() + "=?," +
98              Columns.ISCLIENT.name() + "=?," +
99              Columns.UPDATEDINFO.name() + "=?";
100 
101     protected static final String insertAllValues = " (?,?,?,?,?,?,?,?) ";
102 
103     /* (non-Javadoc)
104      * @see goldengate.common.database.data.AbstractDbData#initObject()
105      */
106     @Override
107     protected void initObject() {
108         primaryKey = new DbValue[]{new DbValue(hostid, Columns.HOSTID
109                 .name())};
110         otherFields = new DbValue[]{
111                 new DbValue(address, Columns.ADDRESS.name()),
112                 new DbValue(port, Columns.PORT.name()),
113                 new DbValue(isSsl, Columns.ISSSL.name()),
114                 new DbValue(hostkey, Columns.HOSTKEY.name()),
115                 new DbValue(adminrole, Columns.ADMINROLE.name()),
116                 new DbValue(isClient, Columns.ISCLIENT.name()),
117                 new DbValue(updatedInfo, Columns.UPDATEDINFO.name()) };
118         allFields = new DbValue[]{
119                 otherFields[0], otherFields[1], otherFields[2],
120                 otherFields[3], otherFields[4], otherFields[5], otherFields[6], primaryKey[0] };
121     }
122 
123     /* (non-Javadoc)
124      * @see goldengate.common.database.data.AbstractDbData#getSelectAllFields()
125      */
126     @Override
127     protected String getSelectAllFields() {
128         return selectAllFields;
129     }
130 
131     /* (non-Javadoc)
132      * @see goldengate.common.database.data.AbstractDbData#getTable()
133      */
134     @Override
135     protected String getTable() {
136         return table;
137     }
138 
139     /* (non-Javadoc)
140      * @see goldengate.common.database.data.AbstractDbData#getInsertAllValues()
141      */
142     @Override
143     protected String getInsertAllValues() {
144         return insertAllValues;
145     }
146 
147     /* (non-Javadoc)
148      * @see goldengate.common.database.data.AbstractDbData#getUpdateAllFields()
149      */
150     @Override
151     protected String getUpdateAllFields() {
152         return updateAllFields;
153     }
154 
155     @Override
156     protected void setToArray() {
157         allFields[Columns.ADDRESS.ordinal()].setValue(address);
158         allFields[Columns.PORT.ordinal()].setValue(port);
159         allFields[Columns.ISSSL.ordinal()].setValue(isSsl);
160         allFields[Columns.HOSTKEY.ordinal()].setValue(hostkey);
161         allFields[Columns.ADMINROLE.ordinal()].setValue(adminrole);
162         allFields[Columns.ISCLIENT.ordinal()].setValue(isClient);
163         allFields[Columns.UPDATEDINFO.ordinal()].setValue(updatedInfo);
164         allFields[Columns.HOSTID.ordinal()].setValue(hostid);
165     }
166 
167     @Override
168     protected void setFromArray() throws GoldenGateDatabaseSqlException {
169         address = (String) allFields[Columns.ADDRESS.ordinal()].getValue();
170         port = (Integer) allFields[Columns.PORT.ordinal()].getValue();
171         isSsl = (Boolean) allFields[Columns.ISSSL.ordinal()].getValue();
172         hostkey = (byte[]) allFields[Columns.HOSTKEY.ordinal()].getValue();
173         adminrole = (Boolean) allFields[Columns.ADMINROLE.ordinal()].getValue();
174         isClient = (Boolean) allFields[Columns.ISCLIENT.ordinal()].getValue();
175         updatedInfo = (Integer) allFields[Columns.UPDATEDINFO.ordinal()]
176                 .getValue();
177         hostid = (String) allFields[Columns.HOSTID.ordinal()].getValue();
178     }
179 
180     /* (non-Javadoc)
181      * @see goldengate.common.database.data.AbstractDbData#getWherePrimaryKey()
182      */
183     @Override
184     protected String getWherePrimaryKey() {
185         return primaryKey[0].column + " = ? ";
186     }
187 
188     /* (non-Javadoc)
189      * @see goldengate.common.database.data.AbstractDbData#setPrimaryKey()
190      */
191     @Override
192     protected void setPrimaryKey() {
193         primaryKey[0].setValue(hostid);
194     }
195 
196     /**
197      * @param dbSession
198      * @param hostid
199      * @param address
200      * @param port
201      * @param isSSL
202      * @param hostkey
203      * @param adminrole
204      * @param isClient
205      */
206     public DbHostAuth(DbSession dbSession, String hostid, String address, int port,
207             boolean isSSL, byte[] hostkey, boolean adminrole, boolean isClient) {
208         super(dbSession);
209         this.hostid = hostid;
210         this.address = address;
211         this.port = port;
212         this.isSsl = isSSL;
213         if (hostkey == null) {
214             this.hostkey = null;
215         } else {
216             try {
217                 // Save as crypted with the local Key and Base64
218                 this.hostkey = Configuration.configuration.cryptoKey.cryptToHex(hostkey).getBytes();
219             } catch (Exception e) {
220                 this.hostkey = new byte[0];
221             }
222         }
223         this.adminrole = adminrole;
224         this.isClient = isClient;
225         setToArray();
226         isSaved = false;
227     }
228 
229     /**
230      * @param dbSession
231      * @param hostid
232      * @throws GoldenGateDatabaseException
233      */
234     public DbHostAuth(DbSession dbSession, String hostid) throws GoldenGateDatabaseException {
235         super(dbSession);
236         this.hostid = hostid;
237         // load from DB
238         select();
239     }
240     /**
241      * Delete all entries (used when purge and reload)
242      * @param dbSession
243      * @return the previous existing array of DbRule
244      * @throws GoldenGateDatabaseException
245      */
246     public static DbHostAuth[] deleteAll(DbSession dbSession) throws GoldenGateDatabaseException {
247         DbHostAuth[] result = getAllHosts(dbSession);
248         if (dbSession == null) {
249             dbR66HostAuthHashMap.clear();
250             return result;
251         }
252         DbPreparedStatement preparedStatement = new DbPreparedStatement(
253                 dbSession);
254         try {
255             preparedStatement.createPrepareStatement("DELETE FROM " + table);
256             preparedStatement.executeUpdate();
257             return result;
258         } finally {
259             preparedStatement.realClose();
260         }
261     }
262     /*
263      * (non-Javadoc)
264      *
265      * @see openr66.databaseold.data.AbstractDbData#delete()
266      */
267     @Override
268     public void delete() throws GoldenGateDatabaseException {
269         if (dbSession == null) {
270             dbR66HostAuthHashMap.remove(this.hostid);
271             isSaved = false;
272             return;
273         }
274         DbPreparedStatement preparedStatement = new DbPreparedStatement(
275                 dbSession);
276         try {
277             preparedStatement.createPrepareStatement("DELETE FROM " + table +
278                     " WHERE " + getWherePrimaryKey());
279             setPrimaryKey();
280             setValues(preparedStatement, primaryKey);
281             int count = preparedStatement.executeUpdate();
282             if (count <= 0) {
283                 throw new GoldenGateDatabaseNoDataException("No row found");
284             }
285             isSaved = false;
286         } finally {
287             preparedStatement.realClose();
288         }
289     }
290 
291     /*
292      * (non-Javadoc)
293      *
294      * @see openr66.databaseold.data.AbstractDbData#insert()
295      */
296     @Override
297     public void insert() throws GoldenGateDatabaseException {
298         if (isSaved) {
299             return;
300         }
301         if (dbSession == null) {
302             dbR66HostAuthHashMap.put(this.hostid, this);
303             isSaved = true;
304             return;
305         }
306         DbPreparedStatement preparedStatement = new DbPreparedStatement(
307                 dbSession);
308         try {
309             preparedStatement.createPrepareStatement("INSERT INTO " + table +
310                     " (" + selectAllFields + ") VALUES " + insertAllValues);
311             setValues(preparedStatement, allFields);
312             int count = preparedStatement.executeUpdate();
313             if (count <= 0) {
314                 throw new GoldenGateDatabaseNoDataException("No row found");
315             }
316             isSaved = true;
317         } finally {
318             preparedStatement.realClose();
319         }
320     }
321 
322     /* (non-Javadoc)
323      * @see openr66.databaseold.data.AbstractDbData#exist()
324      */
325     @Override
326     public boolean exist() throws GoldenGateDatabaseException {
327         if (dbSession == null) {
328             return dbR66HostAuthHashMap.containsKey(hostid);
329         }
330         DbPreparedStatement preparedStatement = new DbPreparedStatement(
331                 dbSession);
332         try {
333             preparedStatement.createPrepareStatement("SELECT " +
334                     primaryKey[0].column + " FROM " + table + " WHERE " +
335                     getWherePrimaryKey());
336             setPrimaryKey();
337             setValues(preparedStatement, primaryKey);
338             preparedStatement.executeQuery();
339             return preparedStatement.getNext();
340         } finally {
341             preparedStatement.realClose();
342         }
343     }
344     /*
345      * (non-Javadoc)
346      *
347      * @see openr66.databaseold.data.AbstractDbData#select()
348      */
349     @Override
350     public void select() throws GoldenGateDatabaseException {
351         if (dbSession == null) {
352             DbHostAuth host = dbR66HostAuthHashMap.get(this.hostid);
353             if (host == null) {
354                 throw new GoldenGateDatabaseNoDataException("No row found");
355             } else {
356                 // copy info
357                 for (int i = 0; i < allFields.length; i++){
358                     allFields[i].value = host.allFields[i].value;
359                 }
360                 setFromArray();
361                 isSaved = true;
362                 return;
363             }
364         }
365         DbPreparedStatement preparedStatement = new DbPreparedStatement(
366                 dbSession);
367         try {
368             preparedStatement.createPrepareStatement("SELECT " +
369                     selectAllFields + " FROM " + table + " WHERE " +
370                     getWherePrimaryKey());
371             setPrimaryKey();
372             setValues(preparedStatement, primaryKey);
373             preparedStatement.executeQuery();
374             if (preparedStatement.getNext()) {
375                 getValues(preparedStatement, allFields);
376                 setFromArray();
377                 isSaved = true;
378             } else {
379                 throw new GoldenGateDatabaseNoDataException("No row found");
380             }
381         } finally {
382             preparedStatement.realClose();
383         }
384     }
385 
386     /*
387      * (non-Javadoc)
388      *
389      * @see openr66.databaseold.data.AbstractDbData#update()
390      */
391     @Override
392     public void update() throws GoldenGateDatabaseException {
393         if (isSaved) {
394             return;
395         }
396         if (dbSession == null) {
397             dbR66HostAuthHashMap.put(this.hostid, this);
398             isSaved = true;
399             return;
400         }
401         DbPreparedStatement preparedStatement = new DbPreparedStatement(
402                 dbSession);
403         try {
404             preparedStatement.createPrepareStatement("UPDATE " + table +
405                     " SET " + updateAllFields + " WHERE " +
406                     getWherePrimaryKey());
407             setValues(preparedStatement, allFields);
408             int count = preparedStatement.executeUpdate();
409             if (count <= 0) {
410                 throw new GoldenGateDatabaseNoDataException("No row found");
411             }
412             isSaved = true;
413         } finally {
414             preparedStatement.realClose();
415         }
416     }
417     /**
418      * Private constructor for Commander only
419      */
420     private DbHostAuth(DbSession session) {
421         super(session);
422     }
423     /**
424      * Get All DbHostAuth from database or from internal hashMap in case of no database support
425      * @param dbSession may be null
426      * @return the array of DbHostAuth
427      * @throws GoldenGateDatabaseNoConnectionException
428      * @throws GoldenGateDatabaseSqlException
429      */
430     public static DbHostAuth[] getAllHosts(DbSession dbSession) throws GoldenGateDatabaseNoConnectionException, GoldenGateDatabaseSqlException {
431         if (dbSession == null) {
432             DbHostAuth [] result = new DbHostAuth[0];
433             return dbR66HostAuthHashMap.values().toArray(result);
434         }
435         String request = "SELECT " +selectAllFields;
436             request += " FROM "+table;
437         DbPreparedStatement preparedStatement = new DbPreparedStatement(dbSession, request);
438         ArrayList<DbHostAuth> dbArrayList = new ArrayList<DbHostAuth>();
439         preparedStatement.executeQuery();
440         while (preparedStatement.getNext()) {
441             DbHostAuth hostAuth = getFromStatement(preparedStatement);
442             dbArrayList.add(hostAuth);
443         }
444         preparedStatement.realClose();
445         DbHostAuth [] result = new DbHostAuth[0];
446         dbArrayList.toArray(result);
447         return result;
448     }
449     /**
450      * For instance from Commander when getting updated information
451      * @param preparedStatement
452      * @return the next updated DbHostAuth
453      * @throws GoldenGateDatabaseNoConnectionException
454      * @throws GoldenGateDatabaseSqlException
455      */
456     public static DbHostAuth getFromStatement(DbPreparedStatement preparedStatement) throws GoldenGateDatabaseNoConnectionException, GoldenGateDatabaseSqlException {
457         DbHostAuth dbHostAuth = new DbHostAuth(preparedStatement.getDbSession());
458         dbHostAuth.getValues(preparedStatement, dbHostAuth.allFields);
459         dbHostAuth.setFromArray();
460         dbHostAuth.isSaved = true;
461         return dbHostAuth;
462     }
463     /**
464     *
465     * @return the DbPreparedStatement for getting Updated Object
466     * @throws GoldenGateDatabaseNoConnectionException
467     * @throws GoldenGateDatabaseSqlException
468     */
469    public static DbPreparedStatement getUpdatedPrepareStament(DbSession session) throws GoldenGateDatabaseNoConnectionException, GoldenGateDatabaseSqlException {
470        String request = "SELECT " +selectAllFields;
471        request += " FROM "+table+
472            " WHERE "+Columns.UPDATEDINFO.name()+" = "+
473            AbstractDbData.UpdatedInfo.TOSUBMIT.ordinal();
474        DbPreparedStatement prep = new DbPreparedStatement(session, request);
475        return prep;
476    }
477    /**
478     *
479     * @param session
480     * @param host
481     * @param addr
482     * @param ssl
483     * @return the DbPreparedStatement according to the filter
484     * @throws GoldenGateDatabaseNoConnectionException
485     * @throws GoldenGateDatabaseSqlException
486     */
487    public static DbPreparedStatement getFilterPrepareStament(DbSession session,
488            String host, String addr, boolean ssl)
489        throws GoldenGateDatabaseNoConnectionException, GoldenGateDatabaseSqlException {
490        DbPreparedStatement preparedStatement = new DbPreparedStatement(session);
491        String request = "SELECT " +selectAllFields+" FROM "+table+" WHERE ";
492        String condition = null;
493        if (host != null) {
494            condition = Columns.HOSTID.name()+" LIKE '%"+host+"%' ";
495        }
496        if (addr != null) {
497            if (condition != null) {
498                condition += " AND ";
499            } else {
500                condition = "";
501            }
502            condition += Columns.ADDRESS.name()+" LIKE '%"+addr+"%' ";
503        }
504        if (condition != null) {
505            condition += " AND ";
506        } else {
507            condition = "";
508        }
509        condition += Columns.ISSSL.name()+" = ?";
510        preparedStatement.createPrepareStatement(request+condition+
511                " ORDER BY "+Columns.HOSTID.name());
512        try {
513            preparedStatement.getPreparedStatement().setBoolean(1, ssl);
514        } catch (SQLException e) {
515            preparedStatement.realClose();
516            throw new GoldenGateDatabaseSqlException(e);
517        }
518        return preparedStatement;
519    }
520 
521     /*
522      * (non-Javadoc)
523      *
524      * @see openr66.databaseold.data.AbstractDbData#changeUpdatedInfo(UpdatedInfo)
525      */
526     @Override
527     public void changeUpdatedInfo(UpdatedInfo info) {
528         if (updatedInfo != info.ordinal()) {
529             updatedInfo = info.ordinal();
530             allFields[Columns.UPDATEDINFO.ordinal()].setValue(updatedInfo);
531             isSaved = false;
532         }
533     }
534 
535     /**
536      * Is the given key a valid one
537      *
538      * @param newkey
539      * @return True if the key is valid (or any key is valid)
540      */
541     public boolean isKeyValid(byte[] newkey) {
542         // It is valid to not have a key
543         if (this.hostkey == null) {
544             return true;
545         }
546         if (newkey == null) {
547             return false;
548         }
549         try {
550             return FilesystemBasedDigest.equalPasswd(
551                     Configuration.configuration.cryptoKey.decryptHexInBytes(this.hostkey), 
552                     newkey);
553         } catch (Exception e) {
554             return false;
555         }
556     }
557 
558     /**
559      * @return the hostkey
560      */
561     public byte[] getHostkey() {
562         if (hostkey == null) {
563             return null;
564         }
565         try {
566             return Configuration.configuration.cryptoKey.decryptHexInBytes(hostkey);
567         } catch (Exception e) {
568             return new byte[0];
569         }
570     }
571 
572     /**
573      * @return the adminrole
574      */
575     public boolean isAdminrole() {
576         return adminrole;
577     }
578     /**
579      * Test if the address is 0.0.0.0 for a client or isClient
580      * @return True if the address is a client address (0.0.0.0) or isClient
581      */
582     public boolean isClient() {
583         return isClient || (this.address.equals("0.0.0.0"));
584     }
585     /**
586      * True if the address is a client address (0.0.0.0) 
587      * @return True if the address is a client address (0.0.0.0) 
588      */
589     public boolean isNoAddress() {
590         return (this.address.equals("0.0.0.0"));
591     }
592     /**
593      *
594      * @return the SocketAddress from the address and port
595      */
596     public SocketAddress getSocketAddress() {
597         return new InetSocketAddress(this.address, this.port);
598     }
599     /**
600      *
601      * @return True if this Host ref is with SSL support
602      */
603     public boolean isSsl() {
604         return this.isSsl;
605     }
606 
607     /**
608      * @return the hostid
609      */
610     public String getHostid() {
611         return hostid;
612     }
613 
614     /**
615      * @return the address
616      */
617     public String getAddress() {
618         return address;
619     }
620 
621     /**
622      * @return the port
623      */
624     public int getPort() {
625         return port;
626     }
627 
628     @Override
629     public String toString() {
630         return "HostAuth: " + hostid + " address: " +address+":"+port+" isSSL: "+isSsl+
631         " admin: "+ adminrole +" isClient: "+isClient+" ("+(hostkey!=null?hostkey.length:0)+")";
632     }
633     /**
634      * @param session
635      * @param body
636      * @param crypted True if the Key is kept crypted, False it will be in clear form
637      * @return the runner in Html format specified by body by replacing all instance of fields
638      */
639     public String toSpecializedHtml(R66Session session, String body, boolean crypted) {
640         StringBuilder builder = new StringBuilder(body);
641         GgStringUtils.replace(builder, "XXXHOSTXXX", hostid);
642         GgStringUtils.replace(builder, "XXXADDRXXX", address);
643         GgStringUtils.replace(builder, "XXXPORTXXX", Integer.toString(port));
644         if (crypted) {
645             GgStringUtils.replace(builder, "XXXKEYXXX", new String(hostkey));
646         } else {
647             try {
648                 GgStringUtils.replace(builder, "XXXKEYXXX",
649                         Configuration.configuration.cryptoKey.decryptHexInString(new String(this.hostkey)));
650             } catch (Exception e) {
651                 GgStringUtils.replace(builder, "XXXKEYXXX", "BAD DECRYPT");
652             }
653         }
654         GgStringUtils.replace(builder, "XXXSSLXXX", isSsl ? "checked": "");
655         GgStringUtils.replace(builder, "XXXADMXXX", adminrole ? "checked": "");
656         GgStringUtils.replace(builder, "XXXISCXXX", isClient ? "checked": "");
657         int nb = NetworkTransaction.existConnection(getSocketAddress(), getHostid());
658         GgStringUtils.replace(builder, "XXXCONNXXX", (nb > 0)
659                 ? "("+nb+" Connected) ": "");
660         return builder.toString();
661     }
662 }