From dd9e461075a23bc75f9db708609a9d0f0ece3901 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 31 Aug 2018 13:13:07 +0200 Subject: more updates --- .../properties/external_statuscodes_map.properties | 2 + .../properties/status_messages_en.properties | 2 + .../specific/connector/MSConnectorEventCodes.java | 3 + eidas_modules/authmodule-eIDAS-v2/pom.xml | 7 + .../modules/authmodule_eIDASv2/Constants.java | 9 +- .../DAO/eIDASPersonalIdStoreDAO.java | 123 ++++++++ .../exception/SQLiteServiceException.java | 17 ++ .../authmodule_eIDASv2/service/eIDASDataStore.java | 328 +++++++++++++++++++++ .../modules/authmodule_eIDASv2/szr/SZRClient.java | 3 +- .../tasks/CreateIdentityLinkTask.java | 75 ++++- .../src/main/resources/eidas_v2_auth.beans.xml | 3 + .../modules/authmodule_eIDASv2/SZRClientTest.java | 62 ++-- .../authmodule_eIDASv2/eIDASDataStoreTest.java | 87 ++++++ .../resources/SpringTest-context_basic_test.xml | 3 + event_code_descr.txt | 4 +- external_error_code_descr.txt | 3 +- 16 files changed, 678 insertions(+), 53 deletions(-) create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/DAO/eIDASPersonalIdStoreDAO.java create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/SQLiteServiceException.java create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASDataStore.java create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/test/eidas/specific/modules/authmodule_eIDASv2/eIDASDataStoreTest.java diff --git a/connector/src/main/resources/properties/external_statuscodes_map.properties b/connector/src/main/resources/properties/external_statuscodes_map.properties index cf26832b..3e299481 100644 --- a/connector/src/main/resources/properties/external_statuscodes_map.properties +++ b/connector/src/main/resources/properties/external_statuscodes_map.properties @@ -67,6 +67,8 @@ internal.01=9199 internal.02=9101 internal.03=9199 internal.04=9101 +internal.05=9106 +internal.06=9106 config.08=9008 config.27=9008 diff --git a/connector/src/main/resources/properties/status_messages_en.properties b/connector/src/main/resources/properties/status_messages_en.properties index e09f3691..f5d084b2 100644 --- a/connector/src/main/resources/properties/status_messages_en.properties +++ b/connector/src/main/resources/properties/status_messages_en.properties @@ -65,6 +65,8 @@ internal.01=The LogOut process stops by reason of an internal problem internal.02=Internal error. Can not access data cache. internal.03=Internal error. Can not initialize a cryptographic method. internal.04=Internal error. Can not access data cache (Reason: {0}). +internal.05=Internal error. Can not access SQLite database for identity-data storage (Reason: {0}) +internal.06=Internal error. Can not query SQLite database for identity-data storage (Reason: {0}) config.08=Configuration value: {0} is missing. config.27=Configuration parameter processing failed. Reason: {0} diff --git a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MSConnectorEventCodes.java b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MSConnectorEventCodes.java index e2915bbf..49a079ff 100644 --- a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MSConnectorEventCodes.java +++ b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/MSConnectorEventCodes.java @@ -15,4 +15,7 @@ public class MSConnectorEventCodes { public static final int SZR_IDL_RECEIVED = 6200; public static final int SZR_BPK_RECEIVED = 6201; + public static final int SZR_ERNB_EIDAS_RAW_ID = 6210; + public static final int SZR_ERNB_EIDAS_HASHED_ID = 6211; + } diff --git a/eidas_modules/authmodule-eIDAS-v2/pom.xml b/eidas_modules/authmodule-eIDAS-v2/pom.xml index 51b3004c..5dae81c3 100644 --- a/eidas_modules/authmodule-eIDAS-v2/pom.xml +++ b/eidas_modules/authmodule-eIDAS-v2/pom.xml @@ -16,6 +16,7 @@ 2.1.0 2.1.0 2.1.0 + 3.23.1 @@ -114,6 +115,12 @@ org.apache.cxf cxf-rt-transports-http + + org.xerial + sqlite-jdbc + ${org.xerial.sqlite-jdbc.version} + + javax.servlet javax.servlet-api diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/Constants.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/Constants.java index 85743585..24d1f1ea 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/Constants.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/Constants.java @@ -61,6 +61,12 @@ public class Constants { public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_AUTHORITY = CONIG_PROPS_EIDAS_SZRCLIENT + ".params.issuingauthority"; public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_KEYS_USEDUMMY= CONIG_PROPS_EIDAS_SZRCLIENT + ".params.usedummykeys"; public static final String CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USESRZFORBPKGENERATION= CONIG_PROPS_EIDAS_SZRCLIENT + ".params.useSZRForbPKCalculation"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETPLACEOFBIRTHIFAVAILABLE= CONIG_PROPS_EIDAS_SZRCLIENT + ".params.setPlaceOfBirthIfAvailable"; + + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_SQLLITEDATASTORE_ACTIVE = CONIG_PROPS_EIDAS_SZRCLIENT + ".workarounds.datastore.sqlite.active"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_REVISIONLOGDATASTORE_ACTIVE = CONIG_PROPS_EIDAS_SZRCLIENT + ".workarounds.datastore.revisionlog.active"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_SQLLITEDATASTORE_URL = CONIG_PROPS_EIDAS_SZRCLIENT + ".workarounds.datastore.sqlite.url"; + //http endpoint descriptions public static final String eIDAS_HTTP_ENDPOINT_SP_POST = "/eidas/light/sp/post"; @@ -75,7 +81,8 @@ public class Constants { public static final String eIDAS_ATTR_PERSONALIDENTIFIER = "PersonIdentifier"; public static final String eIDAS_ATTR_DATEOFBIRTH = "DateOfBirth"; public static final String eIDAS_ATTR_CURRENTGIVENNAME = "FirstName"; - public static final String eIDAS_ATTR_CURRENTFAMILYNAME = "FamilyName"; + public static final String eIDAS_ATTR_CURRENTFAMILYNAME = "FamilyName"; + public static final String eIDAS_ATTR_PLACEOFBIRTH = "PlaceOfBirth"; public static final String eIDAS_ATTR_LEGALPERSONIDENTIFIER = "LegalPersonIdentifier"; public static final String eIDAS_ATTR_LEGALNAME = "LegalName"; diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/DAO/eIDASPersonalIdStoreDAO.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/DAO/eIDASPersonalIdStoreDAO.java new file mode 100644 index 00000000..b0f957a5 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/DAO/eIDASPersonalIdStoreDAO.java @@ -0,0 +1,123 @@ +package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.DAO; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import at.gv.egiz.eaaf.core.impl.data.Pair; + +public class eIDASPersonalIdStoreDAO { + public static final String NAME = "foreigneIDMap"; + + //Enum with all cols of this table + public enum COLS { + timestamp, transactionId, eidasId, eidasSourceCountry, eidasDestinationCountry, ernbId + } + + public enum T { + ID("INTEGER"), + BIGINT("VARCHAR(265)"), + URI("VARCHAR(256)"), + DATE("Long"), + TEXT("TEXT"), + Long("BIGINT"), + Int("INTEGER"), + BLOB("BLOB"), + CC("CHAR(2)"), + BOOL("INTEGER"); + + public String s_; + + private T(String s) { + s_ = s; + } + + @Override + public String toString() { + return s_; + } + } + + //define Cols of the table + public static final List> TABLE_COLS; + static { + List> cols = new ArrayList>(); + cols.add(Pair.newInstance(COLS.timestamp.name(), T.DATE)); + cols.add(Pair.newInstance(COLS.transactionId.name(), T.TEXT)); + cols.add(Pair.newInstance(COLS.eidasId.name(), T.TEXT)); + cols.add(Pair.newInstance(COLS.eidasSourceCountry.name(), T.CC)); + cols.add(Pair.newInstance(COLS.eidasDestinationCountry.name(), T.CC)); + cols.add(Pair.newInstance(COLS.ernbId.name(), T.TEXT)); + + TABLE_COLS = Collections.unmodifiableList(cols); + + } + + public static final String CREATE = "CREATE TABLE " + NAME + + " (" + "id" + " " + T.ID.toString() + + " PRIMARY KEY AUTOINCREMENT, " + buildCreateTableQuery(TABLE_COLS) + ")"; + + public static final String INSERT = "INSERT INTO " + NAME + + "(" + buildInsertQueryKeys(TABLE_COLS) + ")" + + " VALUES (" + buildInsertQueryValues(TABLE_COLS) + ");"; + + public static final String SELECT_BY_ERNB_ID = "SELECT * FROM " + NAME + + " WHERE " + COLS.ernbId.name() + "=?;"; + + public static final String SELECT_BY_EIDAS_RAW_ID = "SELECT * FROM " + NAME + + " WHERE " + COLS.eidasId.name() + "=?" + + " and " + COLS.eidasSourceCountry.name() + "=?" + ";"; + + + /** + * Build a part of a SQL query, which contains the cols of a table that should be created + * + * @param cols List of DB col definitions {@link Pair} + * @return Part of a SQL query, which contains cols that should be created + */ + private static String buildCreateTableQuery(List> cols) { + String sql = ""; + + for (Pair el : cols) { + sql += el.getFirst() + " " + el.getSecond().toString() + ","; + + } + + return sql.substring(0, sql.length()-1); + } + + /** + * Build a part of a SQL query, which contains the cols keys of a table for insert operation + * + * @param cols List of DB col definitions {@link Pair} + * @return Part of a SQL query, which contains cols that should be created + */ + protected static String buildInsertQueryKeys(List> cols) { + String sql = ""; + + for (Pair el : cols) { + sql += el.getFirst() + ","; + + } + + return sql.substring(0, sql.length()-1); + } + + /** + * Build a part of a SQL query, which contains the cols values of a table for insert operation + * + * @param cols List of DB col definitions {@link Pair} + * @return Part of a SQL query, which contains cols that should be created + */ + protected static String buildInsertQueryValues(List> cols) { + String sql = ""; + + for (Pair el : cols) { + sql += "?,"; + + } + + return sql.substring(0, sql.length()-1); + } + +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/SQLiteServiceException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/SQLiteServiceException.java new file mode 100644 index 00000000..1f295db0 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/SQLiteServiceException.java @@ -0,0 +1,17 @@ +package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception; + +public class SQLiteServiceException extends eIDASAuthenticationException { + + private static final long serialVersionUID = 2278259367925102676L; + + public SQLiteServiceException(String internalMsgId, Object[] params, Throwable e) { + super(internalMsgId, params, e); + + } + + public SQLiteServiceException(String internalMsgId, Object[] params) { + super(internalMsgId, params); + + } + +} 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; + + } +} + diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRClient.java index 4840a5e0..458305c6 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRClient.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRClient.java @@ -116,7 +116,8 @@ public class SZRClient { GetIdentityLink getIDL = new GetIdentityLink(); getIDL.setInsertERnP(insertERnP); getIDL.setPersonInfo(personInfo); - getIDL.getKeyValue().addAll(keyValue); + if (keyValue != null) + getIDL.getKeyValue().addAll(keyValue); JAXBContext jaxbContext = JAXBContext.newInstance(GetIdentityLink.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java index 9882bab2..fde56e7c 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java @@ -33,6 +33,7 @@ import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants; import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.SZRCommunicationException; import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAttributeException; import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAuthenticationException; +import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service.eIDASDataStore; import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.szr.SZRClient; import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.utils.eIDASResponseUtils; import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType; @@ -71,6 +72,7 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask { //@Autowired private eIDASAttributeRegistry attrRegistry; @Autowired private IConfiguration basicConfig; @Autowired private SZRClient szrClient; + @Autowired private eIDASDataStore personalIdStore; /* (non-Javadoc) @@ -94,6 +96,7 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask { Object familyNameObj = simpleAttrMap.get(Constants.eIDAS_ATTR_CURRENTFAMILYNAME); Object givenNameObj = simpleAttrMap.get(Constants.eIDAS_ATTR_CURRENTGIVENNAME); Object dateOfBirthObj = simpleAttrMap.get(Constants.eIDAS_ATTR_DATEOFBIRTH); + Object placeOfBirth = simpleAttrMap.get(Constants.eIDAS_ATTR_PLACEOFBIRTH); //check if availabe if (eIdentifierObj == null || !(eIdentifierObj instanceof String)) @@ -159,8 +162,8 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask { PersonInfoType personInfo = new PersonInfoType(); PersonNameType personName = new PersonNameType(); PhysicalPersonType naturalPerson = new PhysicalPersonType(); - TravelDocumentType eDocument = new TravelDocumentType(); - + TravelDocumentType eDocument = new TravelDocumentType(); + naturalPerson.setName(personName ); personInfo.setPerson(naturalPerson ); personInfo.setTravelDocument(eDocument ); @@ -187,14 +190,27 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask { Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE, Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE)); - //TODO: that should be removed - eDocument.setIssueDate(basicConfig.getBasicConfiguration( - Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_DATE)); - eDocument.setIssuingAuthority(basicConfig.getBasicConfiguration( - Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_AUTHORITY)); + //set PlaceOfBirth if available + if (placeOfBirth != null && placeOfBirth instanceof String) { + log.trace("Find 'PlaceOfBirth' attribute: " + placeOfBirth); + if (basicConfig.getBasicMOAIDConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETPLACEOFBIRTHIFAVAILABLE, + false)) { + naturalPerson.setPlaceOfBirth((String) placeOfBirth); + log.trace("Adding 'PlaceOfBirth' to ERnB request ... "); + + } + } - //TODO: keys are not available in eIDAS - List keyValue = dummyCodeForKeys(); + + + //TODO: that should be removed +// eDocument.setIssueDate(basicConfig.getBasicConfiguration( +// Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_DATE)); +// eDocument.setIssuingAuthority(basicConfig.getBasicConfiguration( +// Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_AUTHORITY)); + //List keyValue = dummyCodeForKeys(); + List keyValue = null; IdentityLinkType result = szrClient.getIdentityLinkInRawMode( personInfo, @@ -207,6 +223,25 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask { Element idlFromSZR = (Element)result.getAssertion(); identityLink = new SimpleIdentityLinkAssertionParser(idlFromSZR).parseIdentityLink(); + //write ERnB inputdate into SQLite database + if (basicConfig.getBasicMOAIDConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_SQLLITEDATASTORE_ACTIVE, true)) { + personalIdStore.storeNationalId( + pendingReq.getUniqueTransactionIdentifier(), + eIdentifier, + uniqueId); + + } + + //write ERnB inputdata into revisionlog + if (basicConfig.getBasicMOAIDConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_SQLLITEDATASTORE_ACTIVE, false)) { + revisionsLogger.logEvent(pendingReq, + MSConnectorEventCodes.SZR_ERNB_EIDAS_RAW_ID, (String)eIdentifierObj); + revisionsLogger.logEvent(pendingReq, + MSConnectorEventCodes.SZR_ERNB_EIDAS_HASHED_ID, uniqueId); + + } //get bPK from SZR if (basicConfig.getBasicMOAIDConfigurationBoolean( @@ -354,29 +389,37 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask { final Class parameterizedType = el.getParameterizedType(); if ((DateTime.class).equals(parameterizedType)) { DateTime attribute = eIDASResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList()); - if (attribute != null) + if (attribute != null) { result.put(el.getFriendlyName(), attribute); - else + log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + attribute.toString() ); + + } else log.info("Ignore empty 'DateTime' attribute"); } else if ((PostalAddress.class).equals(parameterizedType)) { PostalAddress addressAttribute = eIDASResponseUtils.translateAddressAttribute(el, attributeMap.get(el).asList()); - if (addressAttribute != null) + if (addressAttribute != null) { result.put(el.getFriendlyName(), addressAttribute); - else + log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + addressAttribute.toString() ); + + } else log.info("Ignore empty 'PostalAddress' attribute"); } else { List natPersonIdObj = eIDASResponseUtils.translateStringListAttribute(el, attributeMap.get(el).asList()); String stringAttr = natPersonIdObj.get(0); - if (StringUtils.isNotEmpty(stringAttr)) + if (StringUtils.isNotEmpty(stringAttr)) { result.put(el.getFriendlyName(), stringAttr); - else + log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + stringAttr ); + + } else log.info("Ignore empty 'String' attribute"); } } - + + log.debug("Receive #" + result.size() + " attributes with names: " + result.keySet().toString()); + return result; } diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml index 433a0499..12d23ebf 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml @@ -44,6 +44,9 @@ + + dummyCodeForKeys() throws IOException, NoSuchProviderException, InvalidKeyException { - if (basicConfig.getBasicMOAIDConfigurationBoolean( - Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_KEYS_USEDUMMY, - false)) { - List keyvalueList = new ArrayList(); - try { - // set key values - RSAKeyValueType rsa = new RSAKeyValueType(); - rsa.setExponent(PUBKEY_EXPONENT); - rsa.setModulus(PUBKEY_MODULUS); - - KeyValueType key = new KeyValueType(); - key.setRSAKeyValue(rsa); - keyvalueList.add(key); - - return keyvalueList; - } catch (Exception e) { - log.error("TestCode has an internal ERROR", e); - throw e; - - } - - } +// if (basicConfig.getBasicMOAIDConfigurationBoolean( +// Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_KEYS_USEDUMMY, +// false)) { +// List keyvalueList = new ArrayList(); +// try { +// // set key values +// RSAKeyValueType rsa = new RSAKeyValueType(); +// rsa.setExponent(PUBKEY_EXPONENT); +// rsa.setModulus(PUBKEY_MODULUS); +// +// KeyValueType key = new KeyValueType(); +// key.setRSAKeyValue(rsa); +// keyvalueList.add(key); +// +// return keyvalueList; +// } catch (Exception e) { +// log.error("TestCode has an internal ERROR", e); +// throw e; +// +// } +// +// } return null; diff --git a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/test/eidas/specific/modules/authmodule_eIDASv2/eIDASDataStoreTest.java b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/test/eidas/specific/modules/authmodule_eIDASv2/eIDASDataStoreTest.java new file mode 100644 index 00000000..16865b33 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/test/eidas/specific/modules/authmodule_eIDASv2/eIDASDataStoreTest.java @@ -0,0 +1,87 @@ +package at.asitplus.test.eidas.specific.modules.authmodule_eIDASv2; + +import java.security.MessageDigest; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.Base64Utils; + +import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.SQLiteServiceException; +import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAuthenticationException; +import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service.eIDASDataStore; +import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.utils.eIDASResponseUtils; +import at.gv.egiz.eaaf.core.impl.data.Trible; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/SpringTest-context_basic_test.xml") +public class eIDASDataStoreTest { + + @Autowired private eIDASDataStore dataStore; + + private static final String P1_TRANSID = "123456789"; + private static final String P1_eIDASID = "DE/AT/121asdf1as5f1as6f1asd2f1asdf1asdf1asd23f1asdf1asdf4sd7fsdf1asdf1asd2f1asd56f7asdf4asdfasdf1"; + + private static final String P2_TRANSID = "987654321"; + private static final String P2_eIDASID = "EE/AT/asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd"; + + @Test + public void dummyTest() { + + } + + @Test + public void insertTestOne() throws SQLiteServiceException, eIDASAuthenticationException { + Trible eidasId = eIDASResponseUtils.parseEidasPersonalIdentifier(P1_eIDASID); + String ernbId = createHashFromUniqueId(eidasId.getThird()); + dataStore.storeNationalId( + P1_TRANSID, + eidasId, + ernbId); + + + if (StringUtils.isEmpty(dataStore.getEidasRawNationalId(ernbId)) + && dataStore.getEidasRawNationalId(ernbId).equals(eidasId.getThird())) + throw new SQLiteServiceException("No eIDAS RAW Id in SQLite DB", null); + + if (StringUtils.isEmpty(dataStore.getErnbNationalId(eidasId)) + && dataStore.getErnbNationalId(eidasId).equals(ernbId) ) + throw new SQLiteServiceException("No ERnB Id in SQLite DB", null); + + } + + @Test + public void insertTestTwo() throws SQLiteServiceException, eIDASAuthenticationException { + Trible eidasId = eIDASResponseUtils.parseEidasPersonalIdentifier(P2_eIDASID); + String ernbId = createHashFromUniqueId(eidasId.getThird()); + dataStore.storeNationalId( + P2_TRANSID, + eidasId, + ernbId); + + if (StringUtils.isEmpty(dataStore.getEidasRawNationalId(ernbId)) + && dataStore.getEidasRawNationalId(ernbId).equals(eidasId.getThird())) + throw new SQLiteServiceException("No eIDAS RAW Id in SQLite DB", null); + + if (StringUtils.isEmpty(dataStore.getErnbNationalId(eidasId)) + && dataStore.getErnbNationalId(eidasId).equals(ernbId)) + throw new SQLiteServiceException("No ERnB Id in SQLite DB", null); + + } + + private String createHashFromUniqueId(String uniqueId) throws eIDASAuthenticationException { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] hash = md.digest(uniqueId.getBytes("UTF-8")); + String hashBase64 = new String(Base64Utils.encode(hash), "UTF-8").replaceAll("\r\n", ""); + return hashBase64; + + } catch (Exception ex) { + throw new eIDASAuthenticationException("internal.03", new Object[]{}, ex); + + } + } +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_test.xml b/eidas_modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_test.xml index ae320b27..33454871 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_test.xml +++ b/eidas_modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_test.xml @@ -12,6 +12,9 @@ + + diff --git a/event_code_descr.txt b/event_code_descr.txt index 297a50ab..b76f9dcc 100644 --- a/event_code_descr.txt +++ b/event_code_descr.txt @@ -29,4 +29,6 @@ Code ... Wert ... Beschreibung 6104 ... eIDAS Node response validation failed 6200 ... Personenbindung vom SZR erhalten -6201 ... bPK vom SZR erhalten \ No newline at end of file +6201 ... bPK vom SZR erhalten +6210 ... Raw eIDAS Personal identifier ohne Länderprefix +6211 ... Sha256(Raw eIDAS Personal identifier ohne Länderprefix) für ERnB Eintragung \ No newline at end of file diff --git a/external_error_code_descr.txt b/external_error_code_descr.txt index a729e801..cb8b27a0 100644 --- a/external_error_code_descr.txt +++ b/external_error_code_descr.txt @@ -28,5 +28,6 @@ 9102 ... Fehler beim Erzeugen einer internen Datenstruktur 9103 ... Fehler bei der Verarbeitung eines Templates 9104 ... Fehler bei der Auswahl oder Initialisierung des gewünschten Anmeldeprozesses -9105 ... Fehler bei der Fortführung des Anmeldeprozesses +9105 ... Fehler bei der Fortführung des Anmeldeprozesses +9106 .. Fehler bei Zugriff auf SQLite Datenbank 9199 ... generic internal error -- cgit v1.2.3