From dd9e461075a23bc75f9db708609a9d0f0ece3901 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 31 Aug 2018 13:13:07 +0200 Subject: more updates --- .../authmodule_eIDASv2/service/eIDASDataStore.java | 328 +++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASDataStore.java (limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASDataStore.java') diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASDataStore.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASDataStore.java new file mode 100644 index 00000000..1eed19aa --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASDataStore.java @@ -0,0 +1,328 @@ +package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service; + +import java.io.File; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.time.Instant; +import java.util.Properties; + +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.sqlite.SQLiteConfig; +import org.sqlite.SQLiteConfig.LockingMode; +import org.sqlite.SQLiteConfig.SynchronousMode; +import org.sqlite.SQLiteErrorCode; + +import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants; +import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.DAO.eIDASPersonalIdStoreDAO; +import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.SQLiteServiceException; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.data.Trible; + +@Component +public class eIDASDataStore { + + private static final String SQLITE_JDBC_DRIVER_CLASS = "org.sqlite.JDBC"; + private static final String SQLITE_CONNECTION_PARAM = "jdbc:sqlite:%s"; + private static final boolean sleep = true; + private static final int howLongToSleepOnBusyLock_ = 100; + + private static final Logger log = LoggerFactory.getLogger(eIDASDataStore.class); + + @Autowired private IConfiguration basicConfig; + + private String connectionURL; + private Connection conn = null; + + @PostConstruct + private void initialize() throws SQLiteServiceException { + try { + String sqlLiteDBUrl = basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_SQLLITEDATASTORE_URL, + basicConfig.getConfigurationRootDirectory().toString() + "/sqlite/database.db" + + ); + + log.info("Use SQLite database with URL: " + sqlLiteDBUrl); + + //check if SQLite lib is in Classpath + Class.forName(SQLITE_JDBC_DRIVER_CLASS); + + //open DB connection + boolean isNewFileCreated = false; + + //open file or create file if not already exists + File dbFile = new File(sqlLiteDBUrl); + if (!dbFile.exists()) { + log.info("SQLite database does not exist. Creating new database file ... "); + dbFile.createNewFile(); + isNewFileCreated = true; + + } + + //open database connection + connectionURL = String.format(SQLITE_CONNECTION_PARAM, dbFile.getPath()); + + //create DB scheme if new DB file was created + if (isNewFileCreated) { + executeUpdate(startConnection().createStatement(), eIDASPersonalIdStoreDAO.CREATE); + log.debug("SQLite db scheme created"); + + } + + } catch (ClassNotFoundException e) { + log.warn("Can NOT initialize SQLite database for temporarly identity mapping. ", e); + throw new SQLiteServiceException("internal.05", new Object[] {e.getMessage()}, e); + + } catch (SQLException | IOException e) { + log.warn("Can NOT initialize SQLite database for temporarly identity mapping. ", e); + throw new SQLiteServiceException("internal.05", new Object[] {e.getMessage()}, e); + + } + + } + + + + + /** + * Store a mapping entry with eIDAS personal identifier (source country / destination country / personal identifier) + * and the identifier that is used for ERnB communication + * + * @param transactionId Id of this authentication transaction + * @param eIDASId eIDAS personal identifier without country prefixes + * @param ernbId personal identifier that is used to request the ERnB + * @throws SQLiteServiceException + */ + public void storeNationalId(String transactionId, Trible eIDASId, String ernbId) throws SQLiteServiceException { + try { + PreparedStatement preStatment = startConnection().prepareStatement( + eIDASPersonalIdStoreDAO.INSERT, + Statement.RETURN_GENERATED_KEYS); + + for (int i=1; i<=eIDASPersonalIdStoreDAO.TABLE_COLS.size(); i++) { + Pair col = eIDASPersonalIdStoreDAO.TABLE_COLS.get(i-1); + if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.timestamp.name())) + preStatment.setDate(i, new java.sql.Date(Instant.now().toEpochMilli())); + + else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.transactionId.name())) + preStatment.setString(i, transactionId); + + else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.eidasId.name())) + preStatment.setString(i, eIDASId.getThird()); + + else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.eidasSourceCountry.name())) + preStatment.setString(i, eIDASId.getFirst()); + + else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.eidasDestinationCountry.name())) + preStatment.setString(i, eIDASId.getSecond()); + + else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.ernbId.name())) + preStatment.setString(i, ernbId); + + else + log.warn("SQLite table:" + eIDASPersonalIdStoreDAO.NAME + " contains no col with name:" + col.getFirst()); + + } + + //execute SQL query + int sqlResult = preStatment.executeUpdate(); + + if (sqlResult != 1) { + log.warn("SQLite query execution FAILED!"); + throw new SQLiteServiceException("internal.06", new Object[] {"Queryresult is '-1'"}); + + } + + } catch (SQLiteServiceException | SQLException e) { + log.warn("SQLite query execution FAILED!", e); + throw new SQLiteServiceException("internal.05", new Object[] {e.getMessage()}, e); + + } + + } + + public String getErnbNationalId(Trible eIDASId) throws SQLiteServiceException { + try { + PreparedStatement preStatment = startConnection().prepareStatement( + eIDASPersonalIdStoreDAO.SELECT_BY_EIDAS_RAW_ID, + Statement.RETURN_GENERATED_KEYS); + + preStatment.setString(1, eIDASId.getThird()); + preStatment.setString(2, eIDASId.getFirst()); + + ResultSet rs = preStatment.executeQuery(); + + if(!rs.next()) + return null; + + else + return rs.getString(eIDASPersonalIdStoreDAO.COLS.ernbId.name()); + + } catch (SQLiteServiceException | SQLException e) { + log.warn("SQLite query execution FAILED!", e); + throw new SQLiteServiceException("internal.05", new Object[] {e.getMessage()}, e); + + } + + + } + + public String getEidasRawNationalId(String ernbId) throws SQLiteServiceException { + try { + PreparedStatement preStatment = startConnection().prepareStatement( + eIDASPersonalIdStoreDAO.SELECT_BY_ERNB_ID, + Statement.RETURN_GENERATED_KEYS); + + preStatment.setString(1, ernbId); + + ResultSet rs = preStatment.executeQuery(); + + if(!rs.next()) + return null; + + else + return rs.getString(eIDASPersonalIdStoreDAO.COLS.eidasId.name()); + + } catch (SQLiteServiceException | SQLException e) { + log.warn("SQLite query execution FAILED!", e); + throw new SQLiteServiceException("internal.05", new Object[] {e.getMessage()}, e); + + } + + } + + private Connection startConnection() throws SQLiteServiceException { + int i = howLongToSleepOnBusyLock_; + + while (true) { + try { + if (conn == null) { + log.info("Initializing SQLite database with URL: " + connectionURL + " ... "); + conn = DriverManager.getConnection(connectionURL, getConnectionProperties()); + + } else { + if (!conn.isValid(10)) { + log.info("SQLite connection is not valid any more --> restarting connection ..."); + conn.close(); + conn = DriverManager.getConnection(connectionURL, getConnectionProperties()); + } + } + + log.info("SQLite database connected"); + return conn; + + } catch (SQLException e) { + String msg = e.getLocalizedMessage(); + if (isBusyLocked( e)) { + log.warn(msg, e); + try { + if (sleep) + Thread.sleep(i++); + + } catch (InterruptedException e1) { + throw new SQLiteServiceException("internal.05", new Object[] {e1.getMessage()}, e1); + + } + continue; + + } + throw new SQLiteServiceException("internal.05", new Object[] {e.getMessage()}, e); + + } + } + } + + + /* + * SQLite query code + */ + + protected Properties getConnectionProperties() { + SQLiteConfig config = new SQLiteConfig(); + config.enforceForeignKeys(true); + config.setCacheSize(8000); + config.setLockingMode(LockingMode.NORMAL); + config.setSharedCache(false); + config.setReadUncommited(true); + config.setSynchronous(SynchronousMode.NORMAL); + return config.toProperties(); + + } + + private int executeUpdate(Statement statement, String sql) throws SQLiteServiceException { + int i = 10; + + int rc = -1; + while (true) { + try { + rc = statement.executeUpdate(sql); + break; + + } catch (SQLException e) { + try { + if (executeUpdateError(e, i)) + continue; + else + throw new SQLiteServiceException("internal.06", + new Object[] {e.getMessage()}, e); + + } catch (SQLiteServiceException e1) { + log.warn("\n" + sql + "\n" + e1.getMessage()); + throw e1; + + } + } + } + + return rc; + + } + + private boolean isBusyLocked(SQLException e) { + int eC = e.getErrorCode(); + + if (eC == SQLiteErrorCode.SQLITE_LOCKED.code + || eC == SQLiteErrorCode.SQLITE_BUSY.code) { + log.trace("SQLite db is busy looked"); + return true; + + } + + String msg = e.getMessage(); + if ( msg.contains("[SQLITE_LOCKED]") || msg.contains("[SQLITE_BUSY]")) { + log.trace("SQLite db is busy looked"); + return true; + } + + return false; + } + + private boolean executeUpdateError(SQLException e, int theadSleepCounter) throws SQLiteServiceException { + if (isBusyLocked(e)) { + try { + if (sleep) Thread.sleep(theadSleepCounter++); + + } catch (InterruptedException e1) { + throw new SQLiteServiceException("internal.05", new Object[] {e1.getMessage()}, e1); + + } + + return true; + } + + return false; + + } +} + -- cgit v1.2.3