mirror of
https://github.com/drmartinberger/FueliFinTS.git
synced 2026-08-13 12:33:22 +02:00
Initial drop of Fueli FinTS SCA version.
This commit is contained in:
parent
a6a7b9befb
commit
42b4047bac
290 changed files with 27417 additions and 12 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
# Log file
|
||||
*.log
|
||||
**/log/*
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
|
@ -21,3 +22,8 @@
|
|||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
# IntelliJ files
|
||||
.idea/
|
||||
*.iml
|
||||
**/target/
|
||||
|
|
|
|||
13
LICENSE
13
LICENSE
|
|
@ -175,18 +175,7 @@
|
|||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2021 petaFuel GmbH
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
1
aeskey.properties.example
Normal file
1
aeskey.properties.example
Normal file
|
|
@ -0,0 +1 @@
|
|||
aes_key=youraeskey
|
||||
57
config/fuelifints.properties
Normal file
57
config/fuelifints.properties
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Server Settings:
|
||||
rdh_port = 3000
|
||||
ssl_port = 8443
|
||||
server_ip = 127.0.0.1
|
||||
|
||||
# SSL Keystore:
|
||||
keystore_location = src/main/resources/keystore/your_keystore
|
||||
keysotre_password = yourkeystorepassword
|
||||
|
||||
# Default Bank Settings:
|
||||
bankcode = 12345678
|
||||
bankname = FueliFinTS Testbank
|
||||
|
||||
# RDH Keystore:
|
||||
rdh_keystore_location = rdh.ks
|
||||
rdh_keystore_cipher_alias = rdh_cipher
|
||||
rdh_keystore_signer_alias = rdh_signer
|
||||
rdh_keystore_ds_alias = rdh_ds
|
||||
rdh_keystore_password = yourrdhpassword
|
||||
rdh_keystore_cipher_password = yourrdhpassword
|
||||
rdh_keystore_signer_password = yourrdhpassword
|
||||
rdh_keystore_ds_password = yourrdhpassword
|
||||
# AES key for database encryption
|
||||
aes_key_location=aeskey.properties
|
||||
|
||||
# Cipher Suites
|
||||
use_cipher_suites = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;TLS_RSA_WITH_AES_128_CBC_SHA256;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;TLS_RSA_WITH_AES_128_CBC_SHA;TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;SSL_RSA_WITH_3DES_EDE_CBC_SHA;TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;TLS_EMPTY_RENEGOTIATION_INFO_SCSV;SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA;SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA;SSL_RSA_WITH_RC4_128_MD5
|
||||
|
||||
#don't use following cipher suites:
|
||||
#TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
|
||||
#TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
|
||||
#TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
||||
#TLS_DHE_DSS_WITH_AES_128_CBC_SHA
|
||||
#TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
|
||||
#TLS_ECDHE_RSA_WITH_RC4_128_SHA
|
||||
#SSL_RSA_WITH_RC4_128_SHA
|
||||
#TLS_ECDH_ECDSA_WITH_RC4_128_SHA
|
||||
#TLS_ECDH_RSA_WITH_RC4_128_SHA
|
||||
#SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
|
||||
#SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
|
||||
#SSL_RSA_WITH_RC4_128_MD5
|
||||
|
||||
#protocols
|
||||
use_protocols = TLSv1;TLSv1.1;TLSv1.2;SSLv3;SSLv2Hello
|
||||
|
||||
#don't use following protocols
|
||||
#SSLv2Hello
|
||||
#SSLv3
|
||||
|
||||
#enabled HBCI Security Protocols, changes here needs to update the BPD version or clients won't recognize
|
||||
hbci.security.protocols=PIN_2;RDH_9;RDH_10;RAH_9;RAH_10
|
||||
#dialog request timeout in milliseconds
|
||||
dialog.timeout.millis=60000
|
||||
|
||||
productinfo.csv.filepath=FinTS_Produktregistrierungen_Lizenzdatei.csv
|
||||
productinfo.csv.check=true
|
||||
productinfo.csv.startRow=10
|
||||
15
connectionpool.properties.example
Normal file
15
connectionpool.properties.example
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
db.jdbcurl.12345678=jdbc:mysql://yourdbserver:3306/yourbankdb?characterEncoding=ISO-8859-1
|
||||
db.user.12345678=dbuser
|
||||
db.password.12345678=dbpassword
|
||||
|
||||
db.jdbcurl.23456789=jdbc:mysql://anotherdbserver:3306/anotherbankdb?characterEncoding=ISO-8859-1
|
||||
db.user.23456789=otherdbuser
|
||||
db.password.23456789=otherdbpassword
|
||||
|
||||
db.driverclass=com.mysql.jdbc.Driver
|
||||
|
||||
db.pool.initialsize=1
|
||||
db.pool.maxactive=30
|
||||
db.pool.testonborrow=true
|
||||
db.pool.validationquery=SELECT 1
|
||||
db.pool.maxwait=30000
|
||||
100
src/main/java/net/petafuel/fuelifints/ExecutorManager.java
Normal file
100
src/main/java/net/petafuel/fuelifints/ExecutorManager.java
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
package net.petafuel.fuelifints;
|
||||
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.protocol.FinTSPayload;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSDecryptor;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSEncryptor;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSExecutor;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSInjector;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSParser;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSReplyThread;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ExecutorManager {
|
||||
private static final Logger LOG = LogManager.getLogger(ExecutorManager.class);
|
||||
|
||||
private ThreadPoolExecutor decryptQueue = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(15));
|
||||
private ThreadPoolExecutor parseQueue = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(15));
|
||||
private ThreadPoolExecutor injectionQueue = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(15));
|
||||
private ThreadPoolExecutor executeQueue = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(15));
|
||||
private ThreadPoolExecutor encryptionQueue = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(15));
|
||||
private ThreadPoolExecutor replyQueue = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(15));
|
||||
|
||||
public boolean addToDecryptionQueue(Dialog dialog, FinTSPayload payload, IFinTSDecryptor decryptor) {
|
||||
LOG.trace("addToDecryptionQueue called by {}", new Throwable().getStackTrace()[1].getMethodName());
|
||||
try {
|
||||
decryptor.setPayload(payload);
|
||||
decryptor.setDialog(dialog);
|
||||
decryptQueue.execute(decryptor);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.error("addToDecryptionQueue", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param payload message from client + taskId
|
||||
* @param parser FinTS3 or FinTS4 Parser
|
||||
* @return true, if no problems with adding request to parseQueue occured
|
||||
*/
|
||||
public boolean addToParseQueue(Dialog dialog, FinTSPayload payload, IFinTSParser parser) {
|
||||
LOG.trace("addToParseQueue called by {}", new Throwable().getStackTrace()[1].getMethodName());
|
||||
try {
|
||||
parser.setPayload(payload);
|
||||
parser.setDialog(dialog);
|
||||
parseQueue.execute(parser);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.error("addToParseQueue", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addToInjectionQueue(Dialog dialog, IFinTSInjector injector) {
|
||||
try {
|
||||
injector.setDialog(dialog);
|
||||
injectionQueue.execute(injector);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.error("addToInjectionQueue", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addToExecuteQueue(Dialog dialog, IFinTSExecutor executor) {
|
||||
LOG.trace("addToExecuteQueue");
|
||||
try {
|
||||
executor.setDialog(dialog);
|
||||
executeQueue.execute(executor);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.error("addToExecuteQueue", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addToReplyQueue(final Dialog dialog, final FinTSServer finTSServer, IFinTSReplyThread finTSReplyThread) {
|
||||
LOG.trace("addToReplyQueue");
|
||||
finTSReplyThread.setDialog(dialog);
|
||||
finTSReplyThread.setFinTSServer(finTSServer);
|
||||
try {
|
||||
replyQueue.execute(finTSReplyThread);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LOG.error("addToReplyQueue", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void addToEncryptionQueue(Dialog dialog, IFinTSEncryptor finTSEncryptor) {
|
||||
LOG.trace("addToEncryptionQueue");
|
||||
finTSEncryptor.setDialog(dialog);
|
||||
encryptionQueue.execute(finTSEncryptor);
|
||||
}
|
||||
}
|
||||
266
src/main/java/net/petafuel/fuelifints/FinTSServer.java
Normal file
266
src/main/java/net/petafuel/fuelifints/FinTSServer.java
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
package net.petafuel.fuelifints;
|
||||
|
||||
import net.petafuel.fuelifints.communication.*;
|
||||
import net.petafuel.fuelifints.management.CommunicationManagement;
|
||||
import net.petafuel.fuelifints.protocol.fints3.FinTS3Controller;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
public class FinTSServer {
|
||||
private static final Logger LOG = LogManager.getLogger(FinTSServer.class);
|
||||
|
||||
private final long timeoutMilliseconds;
|
||||
|
||||
private final ArrayList<FinTSCommunicationHandler> runningRequests = new ArrayList<FinTSCommunicationHandler>();
|
||||
private MBeanServer mBeanServer;
|
||||
private CommunicationManagement comManagement;
|
||||
|
||||
private NIOSSLRequestListenerThread nioSSL;
|
||||
private NIOSocketListenerThread nioSocket;
|
||||
private BlockingSSLRequestListenerThread blockingSSL;
|
||||
private BlockingSocketListenerThread blockingSocket;
|
||||
|
||||
private InetAddress serverAdress;
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
LOG.info("* * * Starting FueliFinTS server * * *");
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler((t, e) -> LOG.error("UncaughtException in {}", t, e));
|
||||
|
||||
FinTSServer server = new FinTSServer();
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Exception in FueliFinTS", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void stop() {
|
||||
|
||||
try {
|
||||
LOG.info("Stopping FueliFinTS server...");
|
||||
|
||||
//<< TODO: shutdown all open resources ... sockets etc >>
|
||||
|
||||
this.stopListeners();
|
||||
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Exception stopping!", ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public FinTSServer() {
|
||||
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
BufferedInputStream stream = new BufferedInputStream(new FileInputStream("config/fuelifints.properties"));
|
||||
properties.load(stream);
|
||||
stream.close();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Die Datei fuelifints.properties konnte nicht geladen werden.");
|
||||
LOG.error(e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<String> enums = (Enumeration<String>) properties.propertyNames();
|
||||
while (enums.hasMoreElements()) {
|
||||
String key = enums.nextElement();
|
||||
String value = properties.getProperty(key);
|
||||
System.setProperty(key, value);
|
||||
}
|
||||
|
||||
//Diverse Serverparameter können über die Java Console geändert werden, dafür wird die CommunicationManagement Klasse genutzt:
|
||||
comManagement = new CommunicationManagement();
|
||||
timeoutMilliseconds = Long.parseLong(System.getProperty(CommunicationManagement.DIALOG_TIMEOUT_MILLIS, "10000"));
|
||||
|
||||
IFinTSController controller = FinTS3Controller.getInstance();
|
||||
controller.setFinTSServer(this);
|
||||
registerMBeans();
|
||||
|
||||
//Es erfolgt der Start der Listener für Socket und HTTPS Verbindungen:
|
||||
startListeners(comManagement.isNioMode());
|
||||
}
|
||||
|
||||
private void startListeners(boolean nioMode) {
|
||||
if (comManagement.getServer_ip() != null
|
||||
&& !comManagement.getServer_ip().isEmpty()
|
||||
&& !comManagement.getServer_ip().equals("127.0.0.1"))
|
||||
try {
|
||||
this.serverAdress = InetAddress.getByName(comManagement.getServer_ip());
|
||||
} catch (UnknownHostException e) {
|
||||
LOG.error("Unknown Host: {}", comManagement.getServer_ip(), e);
|
||||
}
|
||||
|
||||
try {
|
||||
this.stopListeners();
|
||||
if (nioMode) {
|
||||
if (comManagement.getSslPort() != 0) {
|
||||
nioSSL = new NIOSSLRequestListenerThread(comManagement.getSslPort(), this);
|
||||
nioSSL.start();
|
||||
}
|
||||
if (comManagement.getSocketPort() != 0) {
|
||||
nioSocket = new NIOSocketListenerThread(comManagement.getSocketPort(), this);
|
||||
nioSocket.start();
|
||||
}
|
||||
} else {
|
||||
if (comManagement.getSocketPort() != 0) {
|
||||
blockingSocket = new BlockingSocketListenerThread(comManagement.getSocketPort(), this);
|
||||
blockingSocket.start();
|
||||
}
|
||||
if (comManagement.getSslPort() != 0) {
|
||||
blockingSSL = new BlockingSSLRequestListenerThread(comManagement.getSslPort(), this);
|
||||
blockingSSL.start();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error starting ServerListernerThreads: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerMBeans() {
|
||||
try {
|
||||
mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
|
||||
ObjectName cmName = new ObjectName("net.petafuel.fuelifints.management:type=CommunicationManagement");
|
||||
mBeanServer.registerMBean(comManagement, cmName);
|
||||
mBeanServer.addNotificationListener(cmName, new CommunicationListener(), new CommunicationFilter(), cmName);
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Error registering MBeans", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public InetAddress getServerAdress() {
|
||||
return serverAdress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Beantwortet einen Request
|
||||
*
|
||||
* @param taskId Die ID, die diesem Request zugeordnet ist
|
||||
* @param responseData Ein Byte Array, das als Antwort geschickt werden soll
|
||||
* @param isLastMessage gibt an, ob es sich bei dieser Nachricht um die letzte Nachricht an den Nutzer handelt (ist entwedet bei HKEND (FinTS 3.0) oder eine Fehlernachricht der Fall)
|
||||
*/
|
||||
public boolean respond(int taskId, byte[] responseData, boolean isLastMessage) {
|
||||
|
||||
LOG.debug("isLastMessage? {}", isLastMessage);
|
||||
|
||||
/*
|
||||
try {
|
||||
LOG.info("received Response " + new String(responseData, "ISO-8859-1"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
//ISO-8859-1
|
||||
}
|
||||
*/
|
||||
FinTSCommunicationHandler currentRequest = null;
|
||||
synchronized (runningRequests) {
|
||||
for (FinTSCommunicationHandler request : runningRequests) {
|
||||
if (request.getTaskId() == taskId) {
|
||||
currentRequest = request;
|
||||
currentRequest.updateTimeStamp();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentRequest != null) {
|
||||
currentRequest.sendResponse(responseData, isLastMessage);
|
||||
if (isLastMessage) {
|
||||
currentRequest.setTimestamp(0);
|
||||
}
|
||||
cleanRunningRequests();
|
||||
} else {
|
||||
LOG.error("could not find running request");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class CommunicationFilter implements NotificationFilter {
|
||||
public boolean isNotificationEnabled(Notification n) {
|
||||
return (n.getType().equals("jmx.attribute.change"));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean addRequest(FinTSCommunicationHandler req) {
|
||||
synchronized (runningRequests) {
|
||||
if (!runningRequests.contains(req)) {
|
||||
runningRequests.add(req);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void cleanRunningRequests() {
|
||||
long currentTimeStamp = new Date().getTime();
|
||||
synchronized (runningRequests) {
|
||||
Iterator<FinTSCommunicationHandler> iterator = runningRequests.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
FinTSCommunicationHandler handler = iterator.next();
|
||||
if ((currentTimeStamp - handler.getTimestamp()) > timeoutMilliseconds) {
|
||||
LOG.debug("Removing ... {}", handler);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopListeners() {
|
||||
try {
|
||||
if (blockingSSL != null && blockingSSL.isAlive())
|
||||
blockingSSL.stopListening();
|
||||
|
||||
if (blockingSocket != null && blockingSocket.isAlive())
|
||||
blockingSocket.stopListening();
|
||||
|
||||
if (nioSSL != null && nioSSL.isAlive())
|
||||
nioSSL.stopListening();
|
||||
|
||||
if (nioSocket != null && nioSocket.isAlive())
|
||||
nioSocket.stopListening();
|
||||
|
||||
while (true) {
|
||||
//wait for Threads to finish executing
|
||||
if ((blockingSocket != null && blockingSocket.isAlive()) ||
|
||||
blockingSSL != null && blockingSSL.isAlive()) {
|
||||
Thread.sleep(200);
|
||||
} else if ((nioSSL != null && nioSSL.isAlive()) ||
|
||||
nioSocket != null && nioSocket.isAlive()) {
|
||||
Thread.sleep(200);
|
||||
} else break;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error starting ServerListernerThreads!", e);
|
||||
}
|
||||
}
|
||||
|
||||
class CommunicationListener implements NotificationListener {
|
||||
@Override
|
||||
public void handleNotification(Notification notification, Object o) {
|
||||
String type = notification.getType();
|
||||
if (type.equals("jmx.attribute.change")) {
|
||||
LOG.trace(notification.getMessage());
|
||||
startListeners(comManagement.isNioMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package net.petafuel.fuelifints;
|
||||
|
||||
import net.petafuel.fuelifints.communication.FinTSCommunicationHandler;
|
||||
import net.petafuel.fuelifints.protocol.FinTSPayload;
|
||||
import net.petafuel.fuelifints.protocol.fints3.FinTS3Controller;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
|
||||
public class FinTSVersionSwitch {
|
||||
|
||||
public static enum FinTSVersion {
|
||||
FINTS_VERSION_3_0,
|
||||
FINTS_VERSION_4_0,
|
||||
HBCI_VERSION_2_2,
|
||||
FINTS_ERROR
|
||||
}
|
||||
|
||||
public static IFinTSController controller; //for testing purposes
|
||||
|
||||
public static boolean selectController(int taskId, byte[] request, FinTSCommunicationHandler.CommunicationChannel channel) throws UnsupportedEncodingException {
|
||||
FinTSPayload payload = new FinTSPayload(request, taskId);
|
||||
switch (checkFinTSVersion(request)) {
|
||||
case FINTS_VERSION_3_0:
|
||||
if (controller == null)
|
||||
FinTS3Controller.getInstance().newRequest(payload, channel);
|
||||
else
|
||||
controller.newRequest(payload, channel);
|
||||
break;
|
||||
case FINTS_VERSION_4_0:
|
||||
//FinTS 4 wird noch nicht unterstützt!
|
||||
//break;
|
||||
case HBCI_VERSION_2_2:
|
||||
FinTS3Controller.getInstance().replyWithError(taskId, generateVersionNotSupportedError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static FinTSVersion checkFinTSVersion(byte[] request) {
|
||||
String version = new String(request, 23, 3, StandardCharsets.ISO_8859_1);
|
||||
switch (version) {
|
||||
case "300":
|
||||
return FinTSVersion.FINTS_VERSION_3_0;
|
||||
case "220":
|
||||
return FinTSVersion.HBCI_VERSION_2_2;
|
||||
default:
|
||||
return FinTSVersion.FINTS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateVersionNotSupportedError() {
|
||||
String defaultBankcode = "12345678";
|
||||
String defaultBankname = "FueliFinTS Testbank";
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("config/fuelifints.properties"));
|
||||
properties.load(bis);
|
||||
bis.close();
|
||||
defaultBankcode = properties.getProperty("bankcode");
|
||||
defaultBankname = properties.getProperty("bankname");
|
||||
} catch (FileNotFoundException e) {
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
|
||||
return "HNHBK:1:3+000000000194+220+0+1'" +
|
||||
"HIRMG:2:2+9010::HBCI Version wird nicht unterstützt. Bitte aktualisieren Sie Ihr Kundenprodukt'" +
|
||||
"HIBPA:3:2:4+1+280:" + defaultBankcode + "+" + defaultBankname + "+0+1+300'" +
|
||||
"HNHBS:4:1+1'";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package net.petafuel.fuelifints;
|
||||
|
||||
import net.petafuel.fuelifints.exceptions.HBCISyntaxException;
|
||||
|
||||
public class HBCIParseException extends Exception {
|
||||
public HBCIParseException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
public HBCIParseException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
}
|
||||
94
src/main/java/net/petafuel/fuelifints/IFinTSController.java
Normal file
94
src/main/java/net/petafuel/fuelifints/IFinTSController.java
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package net.petafuel.fuelifints;
|
||||
|
||||
import net.petafuel.fuelifints.communication.FinTSCommunicationHandler;
|
||||
import net.petafuel.fuelifints.exceptions.DependencyResolveException;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.model.Message;
|
||||
import net.petafuel.fuelifints.protocol.FinTSPayload;
|
||||
|
||||
/**
|
||||
* Interface für den FinTSController, der den Dialogablauf organisiert
|
||||
*/
|
||||
public interface IFinTSController {
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param payload
|
||||
* @return
|
||||
*/
|
||||
boolean newRequest(FinTSPayload payload, FinTSCommunicationHandler.CommunicationChannel channel);
|
||||
|
||||
/**
|
||||
* Nur für Unit Tests - manuelles Setzen des ExecutorManagers ist normalerweise nicht erforderlich
|
||||
*
|
||||
* @param manager Executormanager, der genutzt werden soll
|
||||
*/
|
||||
void setExecutor(ExecutorManager manager);
|
||||
|
||||
/**
|
||||
* Funktion wird vom {@link net.petafuel.fuelifints.protocol.IFinTSDecryptor} aufgerufen, wenn
|
||||
* die Entschlüsselung der Kundennachricht fertiggestellt ist
|
||||
*
|
||||
* @param payload
|
||||
* @param dialog
|
||||
*/
|
||||
void finishedDecryption(FinTSPayload payload, Dialog dialog);
|
||||
|
||||
/**
|
||||
* Funktion wird vom {@link net.petafuel.fuelifints.protocol.IFinTSParser} aufgerufen, wenn
|
||||
* das Parsing der Kundennachricht abgeschlossen ist
|
||||
*
|
||||
* @param taskId
|
||||
* @param dialog Dialog mit enthaltener Kundennachricht
|
||||
*/
|
||||
void finishedParsing(int taskId, Dialog dialog);
|
||||
|
||||
/**
|
||||
* Wird im {@link net.petafuel.fuelifints.protocol.IFinTSExecutor} vor dem eigentlichen execute aufgerufen,
|
||||
* um die Vorraussetzungen für das Ausführen der Auftragssegmente des Kunden zu setzen
|
||||
*
|
||||
* @param elem
|
||||
* @param dialog
|
||||
* @throws DependencyResolveException
|
||||
*/
|
||||
void injectDependencies(IMessageElement elem, Dialog dialog) throws DependencyResolveException;
|
||||
|
||||
/**
|
||||
* Funktion wird vom {@link net.petafuel.fuelifints.protocol.IFinTSExecutor} aufgerufen, wenn
|
||||
* das Ausführen der Kundenaufträge abgeschlossen und die Antwortsegmente generiert worden sind
|
||||
*
|
||||
* @param msg
|
||||
*/
|
||||
void finishedExecuting(Message msg);
|
||||
|
||||
/**
|
||||
* Funktion wird vom {@link net.petafuel.fuelifints.protocol.IFinTSEncryptor} aufgerufen, wenn
|
||||
* die Antwortnachricht des Servers erfolgreich verschlüsselt wurde
|
||||
*
|
||||
* @param msg
|
||||
*/
|
||||
void finishedEncryption(Message msg);
|
||||
|
||||
/**
|
||||
* Gibt die Anzahl der Dialoge zurück, die gerade laufen und vom FinTSController verwaltet werden
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int getRunningDialogCount();
|
||||
|
||||
|
||||
/**
|
||||
* Nur für Unit Tests, um manuell einen FinTSServer zu setzen (bzw zu mocken)
|
||||
*
|
||||
* @param finTSServer FinTSServer, der vom FinTSController genutzt werden soll
|
||||
*/
|
||||
void setFinTSServer(FinTSServer finTSServer);
|
||||
|
||||
/**
|
||||
* Getter für den aktuell benutzten FinTSServer
|
||||
*
|
||||
* @return FinTSServer, der gerade vom FinTSController genutzt wird
|
||||
*/
|
||||
FinTSServer getFinTSServer();
|
||||
}
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
package net.petafuel.fuelifints.communication;
|
||||
|
||||
import net.petafuel.fuelifints.FinTSServer;
|
||||
import net.petafuel.fuelifints.FinTSVersionSwitch;
|
||||
import org.apache.http.ConnectionClosedException;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpResponseInterceptor;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.impl.DefaultConnectionReuseStrategy;
|
||||
import org.apache.http.impl.DefaultHttpResponseFactory;
|
||||
import org.apache.http.impl.DefaultHttpServerConnection;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.apache.http.params.CoreProtocolPNames;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.params.SyncBasicHttpParams;
|
||||
import org.apache.http.protocol.BasicHttpContext;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.protocol.HttpProcessor;
|
||||
import org.apache.http.protocol.HttpRequestHandler;
|
||||
import org.apache.http.protocol.HttpRequestHandlerRegistry;
|
||||
import org.apache.http.protocol.HttpService;
|
||||
import org.apache.http.protocol.ImmutableHttpProcessor;
|
||||
import org.apache.http.protocol.ResponseConnControl;
|
||||
import org.apache.http.protocol.ResponseContent;
|
||||
import org.apache.http.protocol.ResponseDate;
|
||||
import org.apache.http.protocol.ResponseServer;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Properties;
|
||||
|
||||
public class BlockingSSLRequestListenerThread extends Thread {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(BlockingSSLRequestListenerThread.class);
|
||||
private boolean shouldStop = false;
|
||||
|
||||
|
||||
private final SSLServerSocket serversocket;
|
||||
private final HttpParams params;
|
||||
private final HttpService httpService;
|
||||
|
||||
private FinTSServer finTSServer;
|
||||
|
||||
public BlockingSSLRequestListenerThread(int port, FinTSServer server) throws IOException {
|
||||
this.finTSServer = server;
|
||||
Properties systemProps = System.getProperties();
|
||||
Properties properties = new Properties();
|
||||
String[] useCipherSuites = null;
|
||||
String[] useProtocols = null;
|
||||
try {
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("config/fuelifints.properties"));
|
||||
properties.load(bis);
|
||||
bis.close();
|
||||
systemProps.put("javax.net.ssl.keyStore", properties.getProperty("keystore_location"));
|
||||
systemProps.put("javax.net.ssl.keyStorePassword", properties.getProperty("keysotre_password"));
|
||||
useCipherSuites = properties.getProperty("use_cipher_suites").split(";");
|
||||
useProtocols = properties.getProperty("use_protocols").split(";");
|
||||
} catch (Exception e) {
|
||||
LOG.error("I/O error in constructor", e.getMessage());
|
||||
}
|
||||
System.setProperties(systemProps);
|
||||
|
||||
SSLServerSocketFactory sslsocketfactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
|
||||
|
||||
serversocket = (SSLServerSocket) sslsocketfactory.createServerSocket(port, 0, finTSServer.getServerAdress());
|
||||
if (useCipherSuites != null) {
|
||||
serversocket.setEnabledCipherSuites(useCipherSuites);
|
||||
}
|
||||
if (useProtocols != null) {
|
||||
serversocket.setEnabledProtocols(useProtocols);
|
||||
}
|
||||
this.params = new SyncBasicHttpParams();
|
||||
this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
|
||||
.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
|
||||
.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
|
||||
.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
|
||||
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
|
||||
|
||||
// Set up the HTTP protocol processor
|
||||
HttpProcessor httpproc = new ImmutableHttpProcessor(new HttpResponseInterceptor[]{
|
||||
new ResponseDate(),
|
||||
new ResponseServer(),
|
||||
new ResponseContent(),
|
||||
new ResponseConnControl()
|
||||
});
|
||||
|
||||
// Set up request handlers
|
||||
HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
|
||||
reqistry.register("*", new SslRequestHandler());
|
||||
|
||||
// Set up the HTTP service
|
||||
this.httpService = new HttpService(
|
||||
httpproc,
|
||||
new DefaultConnectionReuseStrategy(),
|
||||
new DefaultHttpResponseFactory(),
|
||||
reqistry,
|
||||
this.params);
|
||||
}
|
||||
|
||||
public void stopListening() {
|
||||
try {
|
||||
shouldStop = true;
|
||||
serversocket.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error in stopListening: ", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("SSLServer listening on port {}", this.serversocket.getLocalPort());
|
||||
shouldStop = false;
|
||||
while (!shouldStop) {
|
||||
try {
|
||||
// Set up HTTP connection
|
||||
LOG.info("Accepting new incoming connection");
|
||||
final Socket socket = this.serversocket.accept();
|
||||
|
||||
new Thread() {
|
||||
public void run() {
|
||||
DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
|
||||
LOG.info("Incoming connection from {}", socket.getInetAddress());
|
||||
try {
|
||||
conn.bind(socket, BlockingSSLRequestListenerThread.this.params);
|
||||
} catch (IOException e) {
|
||||
LOG.error("io exception ", e);
|
||||
}
|
||||
|
||||
HttpContext context = new BasicHttpContext(null);
|
||||
while (conn.isOpen()) {
|
||||
try {
|
||||
BlockingSSLRequestListenerThread.this.httpService.handleRequest(conn, context);
|
||||
} catch (ConnectionClosedException ex) {
|
||||
LOG.debug("Client closed connection");
|
||||
try {
|
||||
conn.shutdown();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOG.error("I/O error", ex.getMessage());
|
||||
LOG.debug("I/O error", ex.getStackTrace());
|
||||
try {
|
||||
conn.shutdown();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
} catch (HttpException ex) {
|
||||
LOG.debug("Unrecoverable HTTP protocol violation", ex);
|
||||
try {
|
||||
conn.shutdown();
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
} /*finally {
|
||||
try {
|
||||
conn.shutdown();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
} catch (InterruptedIOException e) {
|
||||
LOG.error("Blocking SSL Listener interupted", e.getMessage());
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error initializing connection thread", e.getMessage());
|
||||
LOG.debug("I/O error initializing connection thread", e.getStackTrace());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SslRequestHandler implements HttpRequestHandler {
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
|
||||
|
||||
String method = request.getRequestLine().getMethod().toUpperCase();
|
||||
if (!method.equals("POST")) {
|
||||
response.setStatusCode(HttpStatus.SC_METHOD_NOT_ALLOWED);
|
||||
response.removeHeaders("Server");
|
||||
response.setHeader(new BasicHeader("Server", ""));
|
||||
return;
|
||||
|
||||
//throw new MethodNotSupportedException(method + " method not supported");
|
||||
}
|
||||
|
||||
final HttpResponse httpResponse = response;
|
||||
|
||||
FinTSCommunicationHandler handler = new FinTSCommunicationHandler(FinTSCommunicationHandler.CommunicationChannel.SSL) {
|
||||
@Override
|
||||
public void sendResponse(byte[] responseData, boolean isLastMessage) {
|
||||
updateTimeStamp();
|
||||
httpResponse.setStatusCode(HttpStatus.SC_OK);
|
||||
ByteArrayEntity entity = new ByteArrayEntity(Base64.encode(responseData));
|
||||
httpResponse.setEntity(entity);
|
||||
synchronized (httpResponse) {
|
||||
httpResponse.notifyAll();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
finTSServer.addRequest(handler);
|
||||
|
||||
if (request instanceof HttpEntityEnclosingRequest) {
|
||||
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
|
||||
byte[] entityContent = EntityUtils.toByteArray(entity);
|
||||
byte[] decoded = Base64.decode(new String(entityContent));
|
||||
if (FinTSVersionSwitch.selectController(handler.getTaskId(), decoded, FinTSCommunicationHandler.CommunicationChannel.SSL)) {
|
||||
synchronized (httpResponse) {
|
||||
try {
|
||||
httpResponse.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
LOG.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
package net.petafuel.fuelifints.communication;
|
||||
|
||||
import net.petafuel.fuelifints.FinTSServer;
|
||||
import net.petafuel.fuelifints.FinTSVersionSwitch;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class BlockingSocketListenerThread extends Thread {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(BlockingSocketListenerThread.class);
|
||||
private FinTSServer finTSServer;
|
||||
private boolean shouldStop = false;
|
||||
private ServerSocket socket;
|
||||
|
||||
private int port;
|
||||
|
||||
public BlockingSocketListenerThread(int port, FinTSServer server) {
|
||||
this.finTSServer = server;
|
||||
this.port = port;
|
||||
|
||||
}
|
||||
|
||||
public void stopListening() {
|
||||
try {
|
||||
shouldStop = true;
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error while stopListening", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
shouldStop = false;
|
||||
socket = new ServerSocket(port, 0, finTSServer.getServerAdress());
|
||||
LOG.info("SocketServer listening on port {}", socket.getLocalPort());
|
||||
while (!shouldStop) {
|
||||
Socket clientSocket = socket.accept();
|
||||
new SocketWorkerThread(clientSocket).start();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error in run()", e);
|
||||
}
|
||||
}
|
||||
|
||||
class SocketWorkerThread extends Thread {
|
||||
|
||||
private final Object monitor = new Object();
|
||||
private Socket clientSocket;
|
||||
private boolean isLastMessage = false;
|
||||
|
||||
public SocketWorkerThread(Socket clientSocket) {
|
||||
super();
|
||||
this.clientSocket = clientSocket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("New socket connection thread");
|
||||
SocketRequestHandler handler = new SocketRequestHandler(this);
|
||||
finTSServer.addRequest(handler);
|
||||
while (!shouldStop && !isLastMessage) {
|
||||
handler.handle(this.clientSocket);
|
||||
try {
|
||||
if (!isLastMessage) {
|
||||
synchronized (this) {
|
||||
this.wait();
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
LOG.warn("Interrupted Exception", ex);
|
||||
}
|
||||
}
|
||||
try {
|
||||
clientSocket.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Exception closing clientSocket", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SocketRequestHandler extends FinTSCommunicationHandler {
|
||||
private final Object monitor;
|
||||
private Socket clientSocket;
|
||||
private BufferedInputStream bis;
|
||||
private BufferedOutputStream bos;
|
||||
|
||||
public SocketRequestHandler(Object monitor) {
|
||||
super(CommunicationChannel.SOCKET);
|
||||
this.monitor = monitor;
|
||||
}
|
||||
|
||||
private void handle(Socket clientSocket) {
|
||||
LOG.trace("begin handling socket...");
|
||||
try {
|
||||
this.clientSocket = clientSocket;
|
||||
if (bis == null) {
|
||||
bis = new BufferedInputStream(this.clientSocket.getInputStream());
|
||||
}
|
||||
int c;
|
||||
ByteArrayOutputStream inputPuffer = new ByteArrayOutputStream();
|
||||
int i = 0;
|
||||
|
||||
int messageSize = 0;
|
||||
|
||||
while ((c = bis.read()) >= 0) {
|
||||
//receivedMessage += (char) c;
|
||||
inputPuffer.write(c);
|
||||
i++;
|
||||
if (messageSize != 0 && i == messageSize)
|
||||
break;
|
||||
|
||||
// Diese Abbruchbedingung ist HBCI 2 / 3 spezifisch und wird für FinTS 4 nicht mehr funktionieren:
|
||||
if (inputPuffer.size() == 22) { //in den ersten 22 Zeichen einer HBCI Nachricht steht die Nachrichtenlänge
|
||||
try {
|
||||
String responseSize = new String(inputPuffer.toByteArray(), 10, 12, StandardCharsets.ISO_8859_1);
|
||||
messageSize = Integer.parseInt(responseSize);
|
||||
} catch (NumberFormatException nfe) {
|
||||
LOG.error("Exception parsing responseSize as integer", nfe);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inputPuffer.size() > 0) {
|
||||
FinTSVersionSwitch.selectController(this.taskId, inputPuffer.toByteArray(), CommunicationChannel.SOCKET);
|
||||
} else {
|
||||
LOG.info("could not read data");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error in handle(clientSocket)", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendResponse(byte[] response, boolean isLastMessage) {
|
||||
updateTimeStamp();
|
||||
try {
|
||||
if (bos == null) {
|
||||
bos = new BufferedOutputStream(clientSocket.getOutputStream());
|
||||
}
|
||||
bos.write(response);
|
||||
bos.flush();
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error in sendResponse", e);
|
||||
}
|
||||
synchronized (monitor) {
|
||||
((SocketWorkerThread) monitor).isLastMessage = isLastMessage;
|
||||
monitor.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package net.petafuel.fuelifints.communication;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class FinTSCommunicationHandler {
|
||||
|
||||
|
||||
public enum CommunicationChannel {
|
||||
SSL,
|
||||
SOCKET
|
||||
}
|
||||
|
||||
protected int taskId;
|
||||
private long timestamp;
|
||||
private CommunicationChannel communicationChannel;
|
||||
|
||||
public FinTSCommunicationHandler(CommunicationChannel channel) {
|
||||
this.communicationChannel = channel;
|
||||
this.updateTimeStamp();
|
||||
this.taskId = (int) (Math.random() * Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public int getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public abstract void sendResponse(byte[] response, boolean isLastMessage);
|
||||
|
||||
public void updateTimeStamp() {
|
||||
this.timestamp = new Date().getTime();
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
package net.petafuel.fuelifints.communication;
|
||||
|
||||
import net.petafuel.fuelifints.FinTSServer;
|
||||
import net.petafuel.fuelifints.FinTSVersionSwitch;
|
||||
import org.apache.http.*;
|
||||
import org.apache.http.impl.DefaultConnectionReuseStrategy;
|
||||
import org.apache.http.impl.nio.DefaultHttpServerIODispatch;
|
||||
import org.apache.http.impl.nio.DefaultNHttpServerConnection;
|
||||
import org.apache.http.impl.nio.SSLNHttpServerConnectionFactory;
|
||||
import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
|
||||
import org.apache.http.nio.NHttpConnectionFactory;
|
||||
import org.apache.http.nio.NHttpServerConnection;
|
||||
import org.apache.http.nio.entity.NByteArrayEntity;
|
||||
import org.apache.http.nio.protocol.*;
|
||||
import org.apache.http.nio.reactor.IOEventDispatch;
|
||||
import org.apache.http.nio.reactor.ListeningIOReactor;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.apache.http.params.CoreProtocolPNames;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.apache.http.params.SyncBasicHttpParams;
|
||||
import org.apache.http.protocol.*;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.KeyStore;
|
||||
|
||||
public class NIOSSLRequestListenerThread extends Thread {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(NIOSSLRequestListenerThread.class);
|
||||
|
||||
private int port;
|
||||
private FinTSServer finTSServer;
|
||||
private ListeningIOReactor ioReactor;
|
||||
|
||||
public NIOSSLRequestListenerThread(int port, FinTSServer server) {
|
||||
this.port = port;
|
||||
this.finTSServer = server;
|
||||
}
|
||||
|
||||
public void stopListening() {
|
||||
if (ioReactor != null) {
|
||||
try {
|
||||
long gracePeriod = 3000;
|
||||
ioReactor.shutdown(gracePeriod);
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error while shutting down ioReactor (stopListening)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see <a href="http://hc.apache.org/httpcomponents-core-ga/httpcore-nio/examples/org/apache/http/examples/nio/NHttpServer.java">Apache HttpCore NIO Example</a>
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
/*** HTTP Core SSL Server ***/
|
||||
|
||||
// HTTP parameters for the server
|
||||
HttpParams params = new SyncBasicHttpParams();
|
||||
params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
|
||||
.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
|
||||
.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
|
||||
|
||||
// Create HTTP protocol processing chain
|
||||
HttpProcessor httpproc = new ImmutableHttpProcessor(new HttpResponseInterceptor[]{
|
||||
// Use standard server-side protocol interceptors
|
||||
new ResponseDate(),
|
||||
new ResponseServer(),
|
||||
new ResponseContent(),
|
||||
new ResponseConnControl()
|
||||
});
|
||||
|
||||
// Create request handler registry
|
||||
HttpAsyncRequestHandlerRegistry reqistry = new HttpAsyncRequestHandlerRegistry();
|
||||
// Register the default handler for all URIs
|
||||
reqistry.register("*", new NioSSLHandler());
|
||||
|
||||
// Create server-side HTTP protocol handler
|
||||
HttpAsyncService protocolHandler = new HttpAsyncService(
|
||||
httpproc, new DefaultConnectionReuseStrategy(), reqistry, params) {
|
||||
|
||||
@Override
|
||||
public void connected(final NHttpServerConnection conn) {
|
||||
LOG.info("{}: connection open", conn);
|
||||
super.connected(conn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closed(final NHttpServerConnection conn) {
|
||||
LOG.info("{}: connection closed", conn);
|
||||
super.closed(conn);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Create HTTP connection factory
|
||||
NHttpConnectionFactory<DefaultNHttpServerConnection> connFactory;
|
||||
// Initialize SSL context
|
||||
final KeyStore ks = KeyStore.getInstance("JKS");
|
||||
ks.load(new FileInputStream("src/test/resources/keystore/keystore"), "123456".toCharArray());
|
||||
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmfactory.init(ks, "123456".toCharArray());
|
||||
KeyManager[] keymanagers = kmfactory.getKeyManagers();
|
||||
SSLContext sslcontext = SSLContext.getInstance("TLS");
|
||||
sslcontext.init(keymanagers, null, null);
|
||||
connFactory = new SSLNHttpServerConnectionFactory(sslcontext, null, params);
|
||||
|
||||
// Create server-side I/O event dispatch
|
||||
IOEventDispatch ioEventDispatch = new DefaultHttpServerIODispatch(protocolHandler, connFactory);
|
||||
// Create server-side I/O reactor
|
||||
ioReactor = new DefaultListeningIOReactor();
|
||||
try {
|
||||
LOG.info("NIO SSLServer listening on port {}", port);
|
||||
// Listen of the given port
|
||||
ioReactor.listen(new InetSocketAddress(finTSServer.getServerAdress(), port));
|
||||
// Ready to go!
|
||||
ioReactor.execute(ioEventDispatch);
|
||||
} catch (InterruptedIOException ex) {
|
||||
LOG.error("Interrupted", ex);
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error", e);
|
||||
}
|
||||
LOG.info("Shutdown");
|
||||
} catch (Exception e) {
|
||||
LOG.error("Exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
private class NioSSLHandler extends FinTSCommunicationHandler implements HttpAsyncRequestHandler<HttpRequest> {
|
||||
|
||||
HttpResponse response;
|
||||
HttpAsyncExchange exchange;
|
||||
|
||||
public NioSSLHandler() {
|
||||
super(CommunicationChannel.SSL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpAsyncRequestConsumer<HttpRequest> processRequest(HttpRequest request, HttpContext httpContext) throws HttpException, IOException {
|
||||
return new BasicAsyncRequestConsumer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpRequest request, HttpAsyncExchange httpAsyncExchange, HttpContext httpContext) throws HttpException, IOException {
|
||||
finTSServer.addRequest(this);
|
||||
|
||||
this.response = httpAsyncExchange.getResponse();
|
||||
this.exchange = httpAsyncExchange;
|
||||
|
||||
String method = request.getRequestLine().getMethod().toUpperCase();
|
||||
if (!method.equals("POST")) {
|
||||
throw new MethodNotSupportedException(method + " method not supported");
|
||||
}
|
||||
|
||||
if (request instanceof HttpEntityEnclosingRequest) {
|
||||
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
|
||||
byte[] entityContent = EntityUtils.toByteArray(entity);
|
||||
FinTSVersionSwitch.selectController(this.taskId, entityContent, CommunicationChannel.SSL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendResponse(byte[] responseData, boolean isLastMessage) {
|
||||
updateTimeStamp();
|
||||
response.setStatusCode(HttpStatus.SC_OK);
|
||||
NByteArrayEntity entity = new NByteArrayEntity(responseData);
|
||||
response.setEntity(entity);
|
||||
exchange.submitResponse(new BasicAsyncResponseProducer(response));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
package net.petafuel.fuelifints.communication;
|
||||
|
||||
import net.petafuel.fuelifints.FinTSServer;
|
||||
import net.petafuel.fuelifints.FinTSVersionSwitch;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class NIOSocketListenerThread extends Thread {
|
||||
private static final Logger LOG = LogManager.getLogger(NIOSocketListenerThread.class);
|
||||
private int port;
|
||||
private FinTSServer finTSServer;
|
||||
private Selector socketSelector;
|
||||
ByteBuffer buffer = ByteBuffer.allocate(512);
|
||||
CharsetEncoder encoder;
|
||||
CharsetDecoder decoder;
|
||||
ServerSocketChannel serverSocketChannel;
|
||||
private boolean shouldStop = false;
|
||||
|
||||
private ArrayList<NioSocketWorker> runningWorkers = new ArrayList<NioSocketWorker>();
|
||||
|
||||
public NIOSocketListenerThread(int port, FinTSServer server) {
|
||||
this.finTSServer = server;
|
||||
this.port = port;
|
||||
Charset charset = Charset.forName("ISO-8859-1"); //Latin-1
|
||||
encoder = charset.newEncoder();
|
||||
decoder = charset.newDecoder();
|
||||
}
|
||||
|
||||
public void stopListening() {
|
||||
if (socketSelector != null) {
|
||||
try {
|
||||
shouldStop = true;
|
||||
serverSocketChannel.close();
|
||||
socketSelector.wakeup();
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error while shutting down ioReactor (stopListening)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
shouldStop = false;
|
||||
|
||||
socketSelector = Selector.open();
|
||||
|
||||
serverSocketChannel = ServerSocketChannel.open();
|
||||
serverSocketChannel.socket().bind(new InetSocketAddress(finTSServer.getServerAdress(), this.port));
|
||||
serverSocketChannel.configureBlocking(false);
|
||||
|
||||
serverSocketChannel.register(socketSelector, SelectionKey.OP_ACCEPT);
|
||||
|
||||
LOG.info("NIO SocketServer listening on port {}", port);
|
||||
|
||||
while (!shouldStop) {
|
||||
//Check if Worker is ready:
|
||||
for (NioSocketWorker worker : runningWorkers) {
|
||||
if (worker.isReady) {
|
||||
worker.nioSocketClientChannel.keyFor(socketSelector).interestOps(SelectionKey.OP_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
//waiting for events from the selector
|
||||
socketSelector.select();
|
||||
Set keys = socketSelector.selectedKeys();
|
||||
|
||||
for (Iterator i = keys.iterator(); i.hasNext(); ) {
|
||||
SelectionKey key = (SelectionKey) i.next();
|
||||
i.remove();
|
||||
|
||||
if (!key.isValid())
|
||||
continue;
|
||||
|
||||
//isAcceptable?
|
||||
if (key.isAcceptable()) {
|
||||
//get Client socket Channel:
|
||||
SocketChannel client = serverSocketChannel.accept();
|
||||
client.configureBlocking(false);
|
||||
//read to the selector
|
||||
client.register(socketSelector, SelectionKey.OP_READ);
|
||||
continue;
|
||||
}
|
||||
|
||||
//isReadable?
|
||||
if (key.isReadable()) {
|
||||
SocketChannel client = (SocketChannel) key.channel();
|
||||
new NioSocketWorker(client, key);
|
||||
continue;
|
||||
}
|
||||
|
||||
//isWriteable?
|
||||
if (key.isWritable()) {
|
||||
for (NioSocketWorker worker : runningWorkers) {
|
||||
if (worker.isReady && worker.nioSocketClientChannel.equals(key.channel())) {
|
||||
worker.writeResponse();
|
||||
key.interestOps(SelectionKey.OP_READ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error: ", e);
|
||||
} catch (ClosedSelectorException e) {
|
||||
LOG.error("selector closed: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
private class NioSocketWorker extends FinTSCommunicationHandler {
|
||||
private boolean isReady = false;
|
||||
private byte[] response;
|
||||
private SocketChannel nioSocketClientChannel;
|
||||
|
||||
|
||||
private NioSocketWorker(SocketChannel client, SelectionKey key) {
|
||||
super(CommunicationChannel.SOCKET);
|
||||
|
||||
try {
|
||||
//Read Data From ClientSocket:
|
||||
buffer.clear();
|
||||
|
||||
// Read byte coming from the client
|
||||
int numRead = -1;
|
||||
try {
|
||||
numRead = client.read(buffer);
|
||||
} catch (Exception e) {
|
||||
// client is no longer active
|
||||
key.cancel();
|
||||
client.close();
|
||||
LOG.error("Exception", e);
|
||||
}
|
||||
|
||||
if (numRead == -1) {
|
||||
// client shut down channel cleanly
|
||||
key.channel().close();
|
||||
key.cancel();
|
||||
}
|
||||
|
||||
buffer.flip();
|
||||
buffer.clear();
|
||||
|
||||
this.nioSocketClientChannel = client;
|
||||
finTSServer.addRequest(this);
|
||||
if (!runningWorkers.contains(this))
|
||||
runningWorkers.add(this);
|
||||
FinTSVersionSwitch.selectController(this.taskId, buffer.array(), CommunicationChannel.SOCKET);
|
||||
} catch (CharacterCodingException e) {
|
||||
LOG.error("Encoding error", e);
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendResponse(byte[] response, boolean isLastMessage) {
|
||||
updateTimeStamp();
|
||||
LOG.info("Received Response: {}", this.nioSocketClientChannel);
|
||||
this.response = response;
|
||||
this.isReady = true;
|
||||
socketSelector.wakeup();
|
||||
}
|
||||
|
||||
private void writeResponse() {
|
||||
try {
|
||||
nioSocketClientChannel.write(ByteBuffer.wrap(response));
|
||||
this.isReady = false;
|
||||
} catch (IOException e) {
|
||||
LOG.error("I/O error in writeResponse", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
public interface Cryptography {
|
||||
public byte[] decrypt(byte[] encrypted, byte[] key, String bankId);
|
||||
public byte[] encryptMessage(byte[] message, byte[] key, String bankId);
|
||||
public byte[] encryptEncryptionKey(byte[] encryptionKey, String bankId, String userId);
|
||||
public byte[] generateKey();
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
|
||||
public class CryptographyFactory {
|
||||
public static Cryptography getCryptography(SecurityMethod securityMethod) {
|
||||
switch (securityMethod) {
|
||||
case PIN_1:
|
||||
case PIN_2:
|
||||
return new PinTanCryptography();
|
||||
case RDH_10:
|
||||
return new RDH10Cryptography();
|
||||
case RAH_10:
|
||||
return new RAH10Cryptography();
|
||||
case RDH_9:
|
||||
return new RDH9Cryptography();
|
||||
case RAH_9:
|
||||
return new RAH9Cryptography();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacade;
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacadeManager;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.UnrecoverableEntryException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
|
||||
public class KeyManager {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(KeyManager.class);
|
||||
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("config/fuelifints.properties"));
|
||||
properties.load(bis);
|
||||
bis.close();
|
||||
//RDH zeugs ...
|
||||
KEY_STORE_PATH = properties.getProperty("rdh_keystore_location");
|
||||
PRIVATE_KEY_CIPHER_ALIAS = properties.getProperty("rdh_keystore_cipher_alias");
|
||||
PRIVATE_KEY_SIGNER_ALIAS = properties.getProperty("rdh_keystore_signer_alias");
|
||||
PRIVATE_KEY_DS_ALIAS = properties.getProperty("rdh_keystore_ds_alias");
|
||||
KEY_STORE_PASSWORD = properties.getProperty("rdh_keystore_password");
|
||||
CIPHER_ALIAS_PASSWORD = properties.getProperty("rdh_keystore_cipher_password");
|
||||
SIGNER_ALIAS_PASSWORD = properties.getProperty("rdh_keystore_signer_password");
|
||||
DS_ALIAS_PASSWORD = properties.getProperty("rdh_keystore_ds_password");
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Could not read from properties", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static String KEY_STORE_PASSWORD;
|
||||
private static String CIPHER_ALIAS_PASSWORD;
|
||||
private static String SIGNER_ALIAS_PASSWORD;
|
||||
private static String DS_ALIAS_PASSWORD;
|
||||
private static String KEY_STORE_PATH = "rdh.ks";
|
||||
private static String PRIVATE_KEY_CIPHER_ALIAS = "rdh_cipher";
|
||||
private static String PRIVATE_KEY_SIGNER_ALIAS = "rdh_signer";
|
||||
private static String PRIVATE_KEY_DS_ALIAS = "rdh_ds";
|
||||
private static HashMap<String, KeyManager> instances = new HashMap<>();
|
||||
private String bankId;
|
||||
private DataAccessFacade dataAccessFacade;
|
||||
private PrivateKey signingPrivateKey;
|
||||
private PublicKey signingPublicKey;
|
||||
private PrivateKey cipherPrivateKey;
|
||||
private PublicKey cipherPublicKey;
|
||||
private PrivateKey dsPrivateKey;
|
||||
private PublicKey dsPublicKey;
|
||||
|
||||
private KeyManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public static final KeyManager getInstance(String bankId) {
|
||||
KeyManager instance = null;
|
||||
synchronized (instances) {
|
||||
instance = instances.get(bankId);
|
||||
if (instance == null) {
|
||||
instance = new KeyManager();
|
||||
instance.bankId = bankId;
|
||||
instance.dataAccessFacade = DataAccessFacadeManager.getAccessFacade(bankId);
|
||||
instances.put(bankId, instance);
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public PrivateKey getPrivateKey(SecurityMethod securityMethod, String keyType) {
|
||||
if (signingPrivateKey == null) {
|
||||
readKeysFromKeyStore(keyType);
|
||||
}
|
||||
switch (keyType) {
|
||||
case "S":
|
||||
return signingPrivateKey;
|
||||
case "V":
|
||||
return cipherPrivateKey;
|
||||
case "D":
|
||||
return dsPrivateKey;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void readKeysFromKeyStore(String keyType) {
|
||||
try {
|
||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
File keyStoreFile = new File(KEY_STORE_PATH);
|
||||
keyStore.load(new FileInputStream(keyStoreFile), getKeyStorePassword());
|
||||
|
||||
KeyStore.ProtectionParameter protectionParameter = new KeyStore.PasswordProtection(getPrivateKeyAliasPassword(keyType));
|
||||
KeyStore.PrivateKeyEntry privateKeyEntry;
|
||||
privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(PRIVATE_KEY_SIGNER_ALIAS, protectionParameter);
|
||||
signingPrivateKey = privateKeyEntry.getPrivateKey();
|
||||
signingPublicKey = privateKeyEntry.getCertificate().getPublicKey();
|
||||
privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(PRIVATE_KEY_CIPHER_ALIAS, protectionParameter);
|
||||
cipherPrivateKey = privateKeyEntry.getPrivateKey();
|
||||
cipherPublicKey = privateKeyEntry.getCertificate().getPublicKey();
|
||||
privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(PRIVATE_KEY_DS_ALIAS, protectionParameter);
|
||||
dsPrivateKey = privateKeyEntry.getPrivateKey();
|
||||
dsPublicKey = privateKeyEntry.getCertificate().getPublicKey();
|
||||
} catch (KeyStoreException e) {
|
||||
LOG.error("Error while accessing keystore ", e);
|
||||
} catch (CertificateException e) {
|
||||
LOG.error("Error while accessing keystore ", e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("Error while accessing keystore ", e);
|
||||
} catch (UnrecoverableEntryException e) {
|
||||
LOG.error("Error while accessing keystore ", e);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error while accessing keystore ", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private char[] getPrivateKeyAliasPassword(String keyType) {
|
||||
if (keyType.equals("S")) {
|
||||
return SIGNER_ALIAS_PASSWORD.toCharArray();
|
||||
} else if (keyType.equals("C")) {
|
||||
return CIPHER_ALIAS_PASSWORD.toCharArray();
|
||||
} else {
|
||||
return DS_ALIAS_PASSWORD.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
private char[] getKeyStorePassword() {
|
||||
return KEY_STORE_PASSWORD.toCharArray();
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey(SecurityMethod securityMethod, String keyType) {
|
||||
if (!dataAccessFacade.hasKeyPair(securityMethod, keyType)) {
|
||||
readKeysFromKeyStore(keyType);
|
||||
switch (keyType) {
|
||||
case "S":
|
||||
dataAccessFacade.updateKeyPair(securityMethod, "", new String(Base64.encode(signingPublicKey.getEncoded())), keyType, ((RSAPublicKey) signingPublicKey).getModulus(), ((RSAPublicKey) signingPublicKey).getPublicExponent());
|
||||
break;
|
||||
case "V":
|
||||
dataAccessFacade.updateKeyPair(securityMethod, "", new String(Base64.encode(cipherPublicKey.getEncoded())), keyType, ((RSAPublicKey) cipherPublicKey).getModulus(), ((RSAPublicKey) cipherPublicKey).getPublicExponent());
|
||||
break;
|
||||
case "D":
|
||||
dataAccessFacade.updateKeyPair(securityMethod, "", new String(Base64.encode(dsPublicKey.getEncoded())), keyType, ((RSAPublicKey) dsPublicKey).getModulus(), ((RSAPublicKey) dsPublicKey).getPublicExponent());
|
||||
break;
|
||||
}
|
||||
}
|
||||
String encodedPublicKey = dataAccessFacade.getPublicKey(securityMethod, keyType);
|
||||
try {
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(encodedPublicKey));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PublicKey publicKey = keyFactory.generatePublic(keySpec);
|
||||
return publicKey;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
private void generateAndStoreKeyPair(SecurityMethod securityMethod, String keyType) {
|
||||
try {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
|
||||
int bits = 0;
|
||||
switch (securityMethod) {
|
||||
case RDH_9:
|
||||
case RDH_10:
|
||||
case RAH_9:
|
||||
case RAH_10:
|
||||
bits = 2048;
|
||||
break;
|
||||
}
|
||||
keyPairGenerator.initialize(bits, secureRandom);
|
||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||
PublicKey signingPublicKey = keyPair.getPublic();
|
||||
PrivateKey signingPrivateKey = keyPair.getPrivate();
|
||||
String base64PublicKey = new String(Base64.encode(signingPublicKey.getEncoded()));
|
||||
String base64PrivateKey = new String(Base64.encode(signingPrivateKey.getEncoded()));
|
||||
|
||||
try {
|
||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
keyStore.load(null,getKeyStorePassword());
|
||||
|
||||
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(signingPrivateKey);
|
||||
} catch (KeyStoreException e) {
|
||||
|
||||
}
|
||||
|
||||
dataAccessFacade.updateKeyPair(securityMethod, base64PrivateKey, base64PublicKey, keyType);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public boolean addUserPublicKey(String userId, SecurityMethod securityMethod, String keyType, int keyVersion, int keyNumber, PublicKey publicKey) {
|
||||
String base64PublicKey = new String(Base64.encode(publicKey.getEncoded()));
|
||||
return dataAccessFacade.addUserPublicKey(userId, null, securityMethod, base64PublicKey, keyType, keyVersion, keyNumber, ((RSAPublicKey) publicKey).getModulus(), ((RSAPublicKey) publicKey).getPublicExponent());
|
||||
}
|
||||
|
||||
public PublicKey getUserPublicKey(String userId, String customerId, SecurityMethod securityMethod, String keyType, int keyVersion, int keyNumber) {
|
||||
String encodedPublicKey = dataAccessFacade.getUserPublicKey(userId, customerId, securityMethod, keyType, keyVersion, keyNumber);
|
||||
if (encodedPublicKey == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(encodedPublicKey));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PublicKey publicKey = keyFactory.generatePublic(keySpec);
|
||||
return publicKey;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean existsPublicKey(String userId, String customerId, SecurityMethod securityMethod, String keyType, Integer keyVersion, Integer keyNumber) {
|
||||
return dataAccessFacade.existsUserKey(userId, customerId, securityMethod, keyType, keyVersion, keyNumber);
|
||||
}
|
||||
|
||||
public PublicKey getUserPublicKey(String userId, String customerId, SecurityMethod securityMethod, String keyType) {
|
||||
return getUserPublicKey(userId, customerId, securityMethod, keyType, -1, securityMethod.getVersionNumber());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
public class PinTanCryptography implements Cryptography {
|
||||
|
||||
/**
|
||||
* Beim PIN/TAN Verfahren sind die Daten in HNVSD nicht verschlüsselt.
|
||||
* Gilt für HBCI 2.2+ , FinTS 3 - FinTS 4 muss geprüft werden.
|
||||
* @param encrypted
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public byte[] decrypt(byte[] encrypted, byte[] key, String bankId) {
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptMessage(byte[] message, byte[] key, String bankId) {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptEncryptionKey(byte[] encryptionKey, String bankId, String userId) {
|
||||
return encryptionKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateKey() {
|
||||
return new byte[]{0,0,0,0,0,0,0,0};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacade;
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacadeManager;
|
||||
import net.petafuel.fuelifints.dataaccess.dataobjects.ReturnDataObject;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.client.LegitimationInfo;
|
||||
import net.petafuel.fuelifints.protocol.fints3.FinTS3Controller;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHA;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHK;
|
||||
|
||||
public class PinTanSignatureHelper implements SignatureHelper {
|
||||
@Override
|
||||
public ReturnDataObject validateSignature(byte[] bytes, HNSHK hnshk, HNSHA hnsha, Dialog dialog) {
|
||||
/*
|
||||
* In PIN/TAN wird keine Signatur der Nachricht erstellt.
|
||||
* Es werden nur das Passwort und die Tan eingestellt.
|
||||
*/
|
||||
DataAccessFacade dataAccessFacade = DataAccessFacadeManager.getAccessFacade(hnshk.getSchluesselname().getKreditsinstitutkennung().getKreditinstitutscode());
|
||||
String userId = hnshk.getSchluesselname().getBenutzerkennung();
|
||||
String pin = hnsha.getBenutzerdefinierteSignatur().getPin();
|
||||
ReturnDataObject checkSignature = dataAccessFacade.checkUserPin(userId, pin, dialog);
|
||||
if (!checkSignature.isSuccess()) {
|
||||
dialog.getLegitimationsInfo().setUserId(userId);
|
||||
dialog.setUserId(userId);
|
||||
dialog.getLegitimationsInfo().setCustomerId(userId);
|
||||
}
|
||||
String tan = hnsha.getBenutzerdefinierteSignatur().getTan();
|
||||
|
||||
//TAN zwischenspeichern für Prepaid Backend
|
||||
if (dialog.getLegitimationsInfo() != null) {
|
||||
LegitimationInfo legitimationInfo = dialog.getLegitimationsInfo();
|
||||
legitimationInfo.setTanResponse(tan);
|
||||
}
|
||||
|
||||
if (tan == null && dialog.getTransactionInfo() != null && dialog.getLegitimationsInfo().isStrongAuthenticated()) {
|
||||
//falls keine TAN mit geschickt wurde, aber der Kunde stark authentifiziert ist
|
||||
//dann wird auch keine benötigt
|
||||
checkSignature.setSuccess(true);
|
||||
} else if(tan == null && dialog.getTransactionInfo() != null) {
|
||||
//falls eine TAN erwartet, aber keine mitgeliefert wird schlägt die TAN Prüfung fehl
|
||||
//und es sollen keine Aufträge ausgeführt werden, unabhängig ob die PIN korrekt ist
|
||||
checkSignature.setSuccess(false);
|
||||
} else if (dialog.getTransactionInfo() != null && checkSignature.isSuccess()) {
|
||||
//es wurde eine TAN übermittelt und es gibt das Transaktions-Objekt
|
||||
ReturnDataObject checkTan = dataAccessFacade.checkTan(dialog.getDialogId(), dialog.getLegitimationsInfo(), dialog.getClientProductInfo(),tan, dialog.getTransactionInfo().getAuftragsHashwert());
|
||||
checkSignature.setSuccess(checkTan.isSuccess());
|
||||
if(!"".equals(checkTan.getMessage()))
|
||||
{
|
||||
checkSignature.setMessage(checkTan.getMessage());
|
||||
}
|
||||
if(!"".equals(checkTan.getReturnCode()))
|
||||
{
|
||||
checkSignature.setReturnCode(checkTan.getReturnCode());
|
||||
}
|
||||
|
||||
if (checkTan.isSuccess()) {
|
||||
dialog.getLegitimationsInfo().setStrongAuthenticated(true);
|
||||
FinTS3Controller.getInstance().updateLegitimationInfo(dialog.getDialogId(), dialog.getLegitimationsInfo());
|
||||
}
|
||||
}
|
||||
return checkSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] sign(byte[] toSign, HNSHK hnshk) {
|
||||
return null; // Kein Validierungsresultat bei PIN / TAN
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.*;
|
||||
|
||||
public class RAH10Cryptography implements Cryptography {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(RAH10Cryptography.class);
|
||||
|
||||
static {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
private byte[] iv = new byte[16];
|
||||
|
||||
@Override
|
||||
public byte[] decrypt(byte[] encrypted, byte[] key, String bankId) {
|
||||
try {
|
||||
KeyManager keyManager = KeyManager.getInstance(bankId);
|
||||
PrivateKey privateKey = keyManager.getPrivateKey(SecurityMethod.RAH_10, "V");
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/NOPADDING");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] symmetricKey = cipher.doFinal(key);
|
||||
LOG.debug("decryptedKeyLength: {}", symmetricKey.length);
|
||||
|
||||
// Always read the symmetric key as bytes to avoid 0 removal from the beginning of the key
|
||||
// number datatypes will cut leading zeros
|
||||
byte[] temp = new byte[32];
|
||||
System.arraycopy(symmetricKey, 0, temp, 32 - symmetricKey.length, symmetricKey.length);
|
||||
|
||||
symmetricKey = temp;
|
||||
|
||||
SecretKeySpec algorithmParameterSpec = new SecretKeySpec(symmetricKey, "AES");
|
||||
|
||||
Cipher aesCipher = Cipher.getInstance("AES/CBC/NOPADDING");
|
||||
aesCipher.init(Cipher.DECRYPT_MODE, algorithmParameterSpec, new IvParameterSpec(iv));
|
||||
return removeZkaPadding(aesCipher.doFinal(encrypted));
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("An Error occurred during decryption.", e.getMessage());
|
||||
} catch (NoSuchPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e.getMessage());
|
||||
} catch (InvalidKeyException e) {
|
||||
LOG.error("An Error occurred during decryption.", e.getMessage());
|
||||
} catch (BadPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e.getMessage());
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
LOG.error("An Error occurred during decryption.", e.getMessage());
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
LOG.error("An Error occurred during decryption.", e.getMessage());
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
private byte[] removeZkaPadding(byte[] bytes) {
|
||||
int index = bytes.length - 1;
|
||||
for (; index >= 0; index--) {
|
||||
if (bytes[index] == (byte) 0x80) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
byte[] message = new byte[index];
|
||||
System.arraycopy(bytes, 0, message, 0, message.length);
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptMessage(byte[] message, byte[] key, String bankId) {
|
||||
byte[] paddedMessage = zkaPadding(message);
|
||||
|
||||
try {
|
||||
SecretKeySpec algorithmParameterSpec = new SecretKeySpec(key, "AES");
|
||||
Cipher aesCipher = Cipher.getInstance("AES/CBC/NOPADDING");
|
||||
aesCipher.init(Cipher.ENCRYPT_MODE, algorithmParameterSpec, new IvParameterSpec(iv));
|
||||
return aesCipher.doFinal(paddedMessage);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (BadPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
private byte[] zkaPadding(byte[] message) {
|
||||
byte[] paddedMessage;
|
||||
int length = (message.length + 1) % 16;
|
||||
if (length == 0) {
|
||||
paddedMessage = new byte[message.length + 1];
|
||||
System.arraycopy(message, 0, paddedMessage, 0, message.length);
|
||||
paddedMessage[paddedMessage.length - 1] = (byte) 0x80;
|
||||
} else {
|
||||
paddedMessage = new byte[message.length + 1 + (16 - length)];
|
||||
System.arraycopy(message, 0, paddedMessage, 0, message.length);
|
||||
paddedMessage[message.length] = (byte) 0x80;
|
||||
}
|
||||
return paddedMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptEncryptionKey(byte[] encryptionKey, String bankId, String userId) {
|
||||
KeyManager keyManager = KeyManager.getInstance(bankId);
|
||||
PublicKey publicKey = keyManager.getUserPublicKey(userId, null, SecurityMethod.RAH_10, "V");
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/NOPADDING");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
return cipher.doFinal(encryptionKey);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (BadPaddingException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateKey() {
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
byte[] secretKey = new byte[32];
|
||||
secureRandom.nextBytes(secretKey);
|
||||
//starmoney key fix
|
||||
if (secretKey[0] == 0) {
|
||||
secretKey[0] = 1;
|
||||
}
|
||||
LOG.info("SecretKeyLength: {}", secretKey.length);
|
||||
return secretKey;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.*;
|
||||
|
||||
public class RAH9Cryptography implements Cryptography {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(RAH9Cryptography.class);
|
||||
|
||||
static {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
private byte[] iv = new byte[16];
|
||||
|
||||
@Override
|
||||
public byte[] decrypt(byte[] encrypted, byte[] key, String bankId) {
|
||||
try {
|
||||
KeyManager keyManager = KeyManager.getInstance(bankId);
|
||||
PrivateKey privateKey = keyManager.getPrivateKey(SecurityMethod.RAH_9, "V");
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] symmetricKey = cipher.doFinal(key);
|
||||
LOG.debug("decryptedKeyLength: {}", symmetricKey.length);
|
||||
|
||||
SecretKeySpec algorithmParameterSpec = new SecretKeySpec(symmetricKey, "AES");
|
||||
|
||||
Cipher aesCipher = Cipher.getInstance("AES/CBC/NOPADDING");
|
||||
aesCipher.init(Cipher.DECRYPT_MODE, algorithmParameterSpec, new IvParameterSpec(iv));
|
||||
return removeZkaPadding(aesCipher.doFinal(encrypted));
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (BadPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
private byte[] removeZkaPadding(byte[] bytes) {
|
||||
int index = bytes.length - 1;
|
||||
for (; index >= 0; index--) {
|
||||
if (bytes[index] == (byte) 0x80) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
byte[] message = new byte[index];
|
||||
System.arraycopy(bytes, 0, message, 0, message.length);
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptMessage(byte[] message, byte[] key, String bankId) {
|
||||
return new RAH10Cryptography().encryptMessage(message, key, bankId);
|
||||
}
|
||||
|
||||
private byte[] zkaPadding(byte[] message) {
|
||||
byte[] paddedMessage;
|
||||
int length = (message.length + 1) % 16;
|
||||
if (length == 0) {
|
||||
paddedMessage = new byte[message.length + 1];
|
||||
System.arraycopy(message, 0, paddedMessage, 0, message.length);
|
||||
paddedMessage[paddedMessage.length - 1] = (byte) 0x80;
|
||||
} else {
|
||||
paddedMessage = new byte[message.length + 1 + (16 - length)];
|
||||
System.arraycopy(message, 0, paddedMessage, 0, message.length);
|
||||
paddedMessage[message.length] = (byte) 0x80;
|
||||
}
|
||||
return paddedMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptEncryptionKey(byte[] encryptionKey, String bankId, String userId) {
|
||||
KeyManager keyManager = KeyManager.getInstance(bankId);
|
||||
PublicKey publicKey = keyManager.getUserPublicKey(userId, null, SecurityMethod.RAH_9, "V");
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
return cipher.doFinal(encryptionKey);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (BadPaddingException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateKey() {
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
byte[] secretKey = new byte[32];
|
||||
secureRandom.nextBytes(secretKey);
|
||||
//starmoney key fix
|
||||
if (secretKey[0] == 0) {
|
||||
secretKey[0] = 1;
|
||||
}
|
||||
LOG.info("SecretKeyLength: {}", secretKey.length);
|
||||
return secretKey;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Security;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class RDH10Cryptography implements Cryptography {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(RDH10Cryptography.class);
|
||||
|
||||
static {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decrypt(byte[] encrypted, byte[] key, String bankId) {
|
||||
try {
|
||||
KeyManager keyManager = KeyManager.getInstance(bankId);
|
||||
PrivateKey privateKey = keyManager.getPrivateKey(SecurityMethod.RDH_10, "V");
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/NOPADDING");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] symmetricKey = cipher.doFinal(key);
|
||||
LOG.debug("Successfully decrypted the symmetric key. SymmetricKeyLength: {}", symmetricKey.length);
|
||||
LOG.debug("Symmetric Key: {}", Arrays.toString(symmetricKey));
|
||||
|
||||
Cipher cipherTwoKeyTripleDES = new TwoKeyTripleDESCryptography().createCipher(symmetricKey, Cipher.DECRYPT_MODE);
|
||||
|
||||
return cipherTwoKeyTripleDES.doFinal(encrypted);
|
||||
} catch (BadPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (GeneralSecurityException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptMessage(byte[] message, byte[] key, String bankId) {
|
||||
TwoKeyTripleDESCryptography twoKeyTripleDESCryptography = new TwoKeyTripleDESCryptography();
|
||||
try {
|
||||
Cipher twoKeyTripleDesCipher = twoKeyTripleDESCryptography.createCipher(key, Cipher.ENCRYPT_MODE);
|
||||
return twoKeyTripleDesCipher.doFinal(message);
|
||||
} catch (GeneralSecurityException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptEncryptionKey(byte[] encryptionKey, String bankId, String userId) {
|
||||
KeyManager keyManager = KeyManager.getInstance(bankId);
|
||||
PublicKey publicKey = keyManager.getUserPublicKey(userId, null, SecurityMethod.RDH_10, "V");
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/NOPADDING");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
return cipher.doFinal(encryptionKey);
|
||||
} catch (Exception e) {
|
||||
LOG.error("An Error occurred during encryption.", e.getMessage());
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateKey() {
|
||||
return new TwoKeyTripleDESCryptography().generatePassword();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.dataaccess.dataobjects.ReturnDataObject;
|
||||
import net.petafuel.fuelifints.exceptions.ElementParseException;
|
||||
import net.petafuel.fuelifints.exceptions.HBCISyntaxException;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HKSAK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHA;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.SegmentUtil;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Kik;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.OeffentlicherSchluessel;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Schluesselname;
|
||||
import net.petafuel.fuelifints.support.ByteSplit;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.crypto.CryptoException;
|
||||
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||
import org.bouncycastle.crypto.engines.RSAEngine;
|
||||
import org.bouncycastle.crypto.params.RSAKeyParameters;
|
||||
import org.bouncycastle.crypto.signers.PSSSigner;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.util.List;
|
||||
|
||||
public class RDH10SignatureHelper implements SignatureHelper {
|
||||
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(RDH10SignatureHelper.class);
|
||||
|
||||
@Override
|
||||
public ReturnDataObject validateSignature(byte[] bytes, HNSHK hnshk, HNSHA hnsha, Dialog dialog) {
|
||||
Schluesselname schluesselname = hnshk.getSchluesselname();
|
||||
Kik kreditinstitutkennung = schluesselname.getKreditsinstitutkennung();
|
||||
String benutzerkennung = schluesselname.getBenutzerkennung();
|
||||
|
||||
KeyManager keyManager = KeyManager.getInstance(kreditinstitutkennung.getKreditinstitutscode());
|
||||
SecurityMethod securityMethod = SecurityMethod.valueOf(hnshk.getSicherheitsprofil().getSicherheitsverfahren() + "_" + hnshk.getSicherheitsprofil().getSicherheitsverfahrensversion());
|
||||
PublicKey userPublicKey = null;
|
||||
/**
|
||||
* Falls die Schlüssel gerade eingereicht werden existiert noch kein Eintrag in der Datenbank.
|
||||
* Es wird nach dem Segment gesucht welches den Signierschlüssel beinhaltet und falls vorhanden die Signatur geprüft.
|
||||
*/
|
||||
|
||||
if (benutzerkennung != null) {
|
||||
dialog.setUserId(benutzerkennung);
|
||||
}
|
||||
|
||||
if (!keyManager.existsPublicKey(benutzerkennung, null, securityMethod, schluesselname.getSchluesselart(), schluesselname.getSchluesselversion(), schluesselname.getSchluesselnummer())) {
|
||||
List<byte[]> segments = null;
|
||||
try {
|
||||
segments = ByteSplit.split(bytes, ByteSplit.MODE_SEGMENT);
|
||||
} catch (HBCISyntaxException e) {
|
||||
return new ReturnDataObject(false, HBCISyntaxException.class.getSimpleName() + ": " + e.getCause());
|
||||
}
|
||||
if (segments == null || segments.size() == 0) {
|
||||
return new ReturnDataObject(false, "");
|
||||
}
|
||||
HKSAK hksak = null;
|
||||
for (byte[] segment : segments) {
|
||||
if ("HKSAK".equals(SegmentUtil.getSegmentName(segment))) {
|
||||
hksak = new HKSAK(segment);
|
||||
try {
|
||||
hksak.parseElement();
|
||||
} catch (ElementParseException e) {
|
||||
return new ReturnDataObject(false, "");
|
||||
}
|
||||
if ("S".equals(hksak.getSchluesselname().getSchluesselart())) {
|
||||
break;
|
||||
} else {
|
||||
hksak = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hksak == null) {
|
||||
LOG.error("HKSAK for signingkey not found.");
|
||||
//Das benötigte Segment wurde nicht gefunden.
|
||||
return new ReturnDataObject(false, "");
|
||||
}
|
||||
OeffentlicherSchluessel oeffentlicherSchluessel = hksak.getOeffentlicherSchluessel();
|
||||
if (oeffentlicherSchluessel != null) {
|
||||
BigInteger modulus = new BigInteger(1, SegmentUtil.getBytes(oeffentlicherSchluessel.getModulus()));
|
||||
BigInteger exponent = new BigInteger(1, SegmentUtil.getBytes(oeffentlicherSchluessel.getExponent()));
|
||||
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, exponent);
|
||||
try {
|
||||
LOG.debug("generating publickey from data...");
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
userPublicKey = keyFactory.generatePublic(publicKeySpec);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return new ReturnDataObject(false, "");
|
||||
} catch (InvalidKeySpecException e) {
|
||||
return new ReturnDataObject(false, "");
|
||||
}
|
||||
} else {
|
||||
LOG.error("öffentlicher schlüssel nicht vorhanden..");
|
||||
}
|
||||
} else {
|
||||
LOG.debug("PublicKey should be in database...");
|
||||
if (new String(bytes).contains("HKSAK")) {
|
||||
//Schlüsseleinreichung obwohl schon Schlüssel in der Datenbank vorhanden ist:
|
||||
dialog.getLegitimationsInfo().setUserKeysSubmitted(true);
|
||||
return new ReturnDataObject(false, "");
|
||||
}
|
||||
userPublicKey = keyManager.getUserPublicKey(benutzerkennung, null, securityMethod, schluesselname.getSchluesselart(), schluesselname.getSchluesselversion(), schluesselname.getSchluesselnummer());
|
||||
|
||||
}
|
||||
if (userPublicKey == null) {
|
||||
dialog.getLegitimationsInfo().setUserKeysSubmitted(true);
|
||||
LOG.error("public key not found.");
|
||||
return new ReturnDataObject(false, "");
|
||||
}
|
||||
RSAPublicKey rsaPublicKey = (RSAPublicKey) userPublicKey;
|
||||
|
||||
/*
|
||||
byte[] signatureBytes = hnsha.getValidierungsresultat();
|
||||
int offset = 1;
|
||||
for (; offset < signatureBytes.length; offset++) {
|
||||
if (signatureBytes[offset] == 0x40) {
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
byte[] signature = SegmentUtil.getBytes(hnsha.getValidierungsresultat());//new byte[signatureBytes.length - offset];
|
||||
//System.arraycopy(signatureBytes, offset, signature, 0, signature.length);
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = digest.digest(bytes);
|
||||
|
||||
PSSSigner signer = new PSSSigner(new RSAEngine(), new SHA256Digest(), hash.length);
|
||||
signer.init(false, new RSAKeyParameters(false, rsaPublicKey.getModulus(), rsaPublicKey.getPublicExponent()));
|
||||
signer.update(hash, 0, hash.length);
|
||||
|
||||
boolean isSignatureVerified = signer.verifySignature(signature);
|
||||
|
||||
if (isSignatureVerified) {
|
||||
dialog.getLegitimationsInfo().setStrongAuthenticated(true);
|
||||
}
|
||||
|
||||
return new ReturnDataObject(isSignatureVerified, "");
|
||||
|
||||
/*
|
||||
Signature signature = Signature.getInstance("SHA256withRSAandMGF1");
|
||||
signature.initVerify(userPublicKey);
|
||||
signature.update(bytes);
|
||||
return signature.verify(signatureBytes, offset, signatureBytes.length - offset);
|
||||
*/
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
//SHA256withRSA is supported
|
||||
}
|
||||
|
||||
return new ReturnDataObject(false, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] sign(byte[] toSign, HNSHK hnshk) {
|
||||
Schluesselname schluesselname = hnshk.getSchluesselname();
|
||||
Kik kreditinstitutkennung = schluesselname.getKreditsinstitutkennung();
|
||||
|
||||
KeyManager keyManager = KeyManager.getInstance(kreditinstitutkennung.getKreditinstitutscode());
|
||||
SecurityMethod securityMethod = SecurityMethod.valueOf(hnshk.getSicherheitsprofil().getSicherheitsverfahren() + "_" + hnshk.getSicherheitsprofil().getSicherheitsverfahrensversion());
|
||||
LOG.debug("verwendete Schlüsselart: {}", schluesselname.getSchluesselart());
|
||||
PrivateKey privateKey = keyManager.getPrivateKey(securityMethod, schluesselname.getSchluesselart());
|
||||
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = digest.digest(toSign);
|
||||
|
||||
PSSSigner signer = new PSSSigner(new RSAEngine(), new SHA256Digest(), hash.length);
|
||||
signer.init(true, new RSAKeyParameters(true, rsaPrivateKey.getModulus(), rsaPrivateKey.getPrivateExponent()));
|
||||
|
||||
signer.update(hash, 0, hash.length);
|
||||
|
||||
byte[] sig = signer.generateSignature();
|
||||
|
||||
return sig;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
//SHA256withRSA is supported
|
||||
} catch (CryptoException e) {
|
||||
LOG.error("Exception", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Security;
|
||||
|
||||
public class RDH9Cryptography implements Cryptography {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(RDH9Cryptography.class);
|
||||
|
||||
static {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] decrypt(byte[] encrypted, byte[] key, String bankId) {
|
||||
try {
|
||||
KeyManager keyManager = KeyManager.getInstance(bankId);
|
||||
PrivateKey privateKey = keyManager.getPrivateKey(SecurityMethod.RDH_9, "V");
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
byte[] symmetricKey = cipher.doFinal(key);
|
||||
LOG.debug("Successfully decrypted the symmetric key. SymmetricKeyLength: {}", symmetricKey.length);
|
||||
|
||||
Cipher cipherTwoKeyTripleDES = new TwoKeyTripleDESCryptography().createCipher(symmetricKey, Cipher.DECRYPT_MODE);
|
||||
|
||||
return cipherTwoKeyTripleDES.doFinal(encrypted);
|
||||
} catch (BadPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
} catch (GeneralSecurityException e) {
|
||||
LOG.error("An Error occurred during decryption.", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptMessage(byte[] message, byte[] key, String bankId) {
|
||||
return new RDH10Cryptography().encryptMessage(message, key, bankId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] encryptEncryptionKey(byte[] encryptionKey, String bankId, String userId) {
|
||||
KeyManager keyManager = KeyManager.getInstance(bankId);
|
||||
PublicKey publicKey = keyManager.getUserPublicKey(userId, null, SecurityMethod.RDH_9, "V");
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
return cipher.doFinal(encryptionKey);
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (BadPaddingException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
LOG.error("An Error occurred during encryption.", e);
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateKey() {
|
||||
return new RDH10Cryptography().generateKey();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.dataaccess.dataobjects.ReturnDataObject;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHA;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHK;
|
||||
|
||||
public interface SignatureHelper {
|
||||
public ReturnDataObject validateSignature(byte[] bytes, HNSHK hnshk, HNSHA hnsha, Dialog dialog);
|
||||
|
||||
public byte[] sign(byte[] toSign, HNSHK hnshk);
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
|
||||
public class SignatureHelperFactory {
|
||||
|
||||
public static SignatureHelper getSignatureHelper(SecurityMethod method) {
|
||||
switch (method) {
|
||||
case PIN_1:
|
||||
case PIN_2:
|
||||
return new PinTanSignatureHelper();
|
||||
case RDH_9:
|
||||
case RAH_9:
|
||||
case RAH_10:
|
||||
case RDH_10:
|
||||
return new RDH10SignatureHelper();
|
||||
}
|
||||
|
||||
if (method.equals("PIN-1") || method.equals("PIN-2")) {
|
||||
return new PinTanSignatureHelper();
|
||||
} else if (method.equals("RDH-10")) {
|
||||
return new RDH10SignatureHelper();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package net.petafuel.fuelifints.cryptography;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class TwoKeyTripleDESCryptography {
|
||||
|
||||
/**
|
||||
* Mit dieser Methode legt jede erbende Unterklasse fest,
|
||||
* mit welchen Verfahren der geheime Schluessel geniert werden soll
|
||||
*
|
||||
* @param password Passwort mit dem der geheime Schluessel erzeugt wird
|
||||
* @return Geheimer Schluessel
|
||||
* @throws java.security.GeneralSecurityException
|
||||
*
|
||||
*/
|
||||
public SecretKey createSecretKey(byte[] password) throws GeneralSecurityException {
|
||||
return new SecretKeySpec(generate2Key(password), "DESede");
|
||||
}
|
||||
|
||||
private byte[] generate2Key(byte[] password) throws GeneralSecurityException {
|
||||
byte[] startKey = password;
|
||||
if (startKey.length != 16) {
|
||||
throw new GeneralSecurityException("Ungültige Länge für das Passwort. Passwort muss 16 Zeichen haben!");
|
||||
}
|
||||
|
||||
byte[] finalKey = new byte[24];
|
||||
for (int i = 0; i<finalKey.length; i++) {
|
||||
finalKey[i] = getOddParity(startKey[i%startKey.length]);
|
||||
}
|
||||
|
||||
return finalKey.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert eine ungerade Parität fü+r das übergebene byte
|
||||
* Dabei wird das LSB verworfen und durch ein Paritätsbit ersetzt
|
||||
*
|
||||
* @param b byte, dem eine ungerade parität gegeben werden soll
|
||||
* @return byte mit ungerader parität
|
||||
*/
|
||||
private byte getOddParity(byte b) {
|
||||
b = (byte) ((b >>> 1) << 1);
|
||||
return (byte) (b | (checkOddParity(b) ? 0:1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob die Parität des übergebenen bytes ungerade ist
|
||||
* (== ist die Anzahl der gesetzten bits gerade)
|
||||
* (== ergibt ein xor unter jedem bit 1)
|
||||
*
|
||||
* @param b byte, das zu prüfen ist
|
||||
* @return true bei ungerader Parität, ansonsten false
|
||||
*/
|
||||
private boolean checkOddParity(byte b) {
|
||||
return (((b ^
|
||||
(b>>>1) ^
|
||||
(b>>>2) ^
|
||||
(b>>>3) ^
|
||||
(b>>>4) ^
|
||||
(b>>>5) ^
|
||||
(b>>>6) ^
|
||||
(b>>>7)) & 1)==1);
|
||||
}
|
||||
|
||||
public byte[] generatePassword() {
|
||||
//siehe B3.1.1, FinTS 3.0 Security HBCI
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte[] keyBytes = new byte[16];
|
||||
random.nextBytes(keyBytes);
|
||||
//starmoney key fix
|
||||
if (keyBytes[0] == 0) {
|
||||
keyBytes[0] = 1;
|
||||
}
|
||||
return keyBytes;
|
||||
}
|
||||
|
||||
public Cipher createCipher(byte[] password, int mode) throws GeneralSecurityException {
|
||||
if (password == null) {
|
||||
throw new IllegalArgumentException("Parameter password must not be null.");
|
||||
}
|
||||
SecretKey secretKey = createSecretKey(password);
|
||||
|
||||
//Initialisierungsvektor:
|
||||
//X’00 00 00 00 00 00 00 00’
|
||||
//siehe B2.2.2, FinTS 3.0 Security HBCI
|
||||
byte[] iv = new byte[] {
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
|
||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
|
||||
};
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("DESede/CBC/ISO10126Padding");
|
||||
cipher.init(mode, secretKey, ivSpec);
|
||||
return cipher;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package net.petafuel.fuelifints.cryptography.aesencryption;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.Base64;
|
||||
import java.util.Properties;
|
||||
|
||||
public class AESUtil {
|
||||
private static final Logger LOG = LogManager.getLogger(AESUtil.class);
|
||||
|
||||
/**
|
||||
* Expects a payload to encrypt and returns the encryption result as Base64
|
||||
* @param toEncrypt
|
||||
* @return
|
||||
*/
|
||||
public static String aesEncrypt(byte[] toEncrypt) {
|
||||
try {
|
||||
Cipher aesEncrypt = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
||||
SecretKey aesKey=initAESKey();
|
||||
aesEncrypt.init(Cipher.ENCRYPT_MODE, aesKey,new IvParameterSpec(new byte[16]));
|
||||
byte[] byteToEncrypt= toEncrypt;
|
||||
byte[] encryptedData = aesEncrypt.doFinal(byteToEncrypt);
|
||||
return Base64.getEncoder().encodeToString(encryptedData);
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Exception encrypt the payload", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expects a BASE64 encoded encrypted payload and returns the decrypted result
|
||||
* as byte[]
|
||||
* @param toDecrypt
|
||||
* @return
|
||||
*/
|
||||
public static byte[] aesDecrypt(String toDecrypt) {
|
||||
try {
|
||||
Cipher aesDecrypt = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
||||
SecretKey aesKey=initAESKey();
|
||||
byte[] byteToDecrypt=Base64.getDecoder().decode(toDecrypt);
|
||||
IvParameterSpec ivParameterSpec= new IvParameterSpec(new byte[16]);
|
||||
aesDecrypt.init(Cipher.DECRYPT_MODE, aesKey,ivParameterSpec);
|
||||
byte[] decryptedData = aesDecrypt.doFinal(byteToDecrypt);
|
||||
return decryptedData;
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Exception decrypting the payload", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static SecretKeySpec initAESKey() {
|
||||
try {
|
||||
/**
|
||||
* Read BIC and blz from fuelibus.properties
|
||||
*/
|
||||
Properties properties = new Properties();
|
||||
properties.load(new FileInputStream("config/fuelifints.properties"));
|
||||
String keyFileConfig= properties.getProperty("aes_key_location");
|
||||
Properties keyFile= new Properties();
|
||||
keyFile.load(new FileInputStream(keyFileConfig));
|
||||
String aesKeyEncoded = keyFile.getProperty("aes_key");
|
||||
byte[] aesKey = Base64.getDecoder().decode(aesKeyEncoded);
|
||||
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
|
||||
return keySpec;
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Exception", ex);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
1516
src/main/java/net/petafuel/fuelifints/dataaccess/Banking2Access.java
Normal file
1516
src/main/java/net/petafuel/fuelifints/dataaccess/Banking2Access.java
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,398 @@
|
|||
package net.petafuel.fuelifints.dataaccess;
|
||||
|
||||
import net.petafuel.fuelifints.FinTSVersionSwitch;
|
||||
import net.petafuel.fuelifints.dataaccess.dataobjects.*;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.model.client.ClientProductInfo;
|
||||
import net.petafuel.fuelifints.model.client.LegitimationInfo;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Betrag;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungInternational;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungNational;
|
||||
import net.petafuel.fuelifints.support.Payments;
|
||||
import net.petafuel.jsepa.model.Document;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Facade für den Zugriff auf die Daten, die vom FueliFinTS an den Nutzer übermittelt werden können
|
||||
* <p/>
|
||||
* Die Implementierung erfolgt abhängig davon, welches Bankingsystem hinter dem HBCI Server steht
|
||||
*/
|
||||
|
||||
public interface DataAccessFacade {
|
||||
|
||||
/**
|
||||
* Prüft ob ein Schlüsselpar für die Bank existiert
|
||||
*
|
||||
* @param securityMethod Sicherheitsmethode
|
||||
* @param keyType SchlüsselTyp
|
||||
* @return true wenn exisitert
|
||||
*/
|
||||
boolean hasKeyPair(SecurityMethod securityMethod, String keyType);
|
||||
|
||||
void updateKeyPair(SecurityMethod securityMethod, String privateKey, String publicKey, String keyType, BigInteger modulus, BigInteger publicExponent);
|
||||
|
||||
String getPrivateKey(SecurityMethod securityMethod, String keyType);
|
||||
|
||||
String getPublicKey(SecurityMethod securityMethod, String keyType);
|
||||
|
||||
boolean addUserPublicKey(String userId, String customerId, SecurityMethod securityMethod, String pubKey, String keyType, int keyVersion, int keyNumber, BigInteger modulus, BigInteger publicExponent);
|
||||
|
||||
String getUserPublicKey(String userId, String customerId, SecurityMethod securityMethod, String keyType, int keyVersion, int keyNumber);
|
||||
|
||||
boolean existsUserKey(String userId, String customerId, SecurityMethod securityMethod, String keyType, int keyVersion, int keyNumber);
|
||||
|
||||
String getUserSystemId(String dialogid, LegitimationInfo legitimationInfo, ClientProductInfo clientPoductInfo);
|
||||
|
||||
String getOrGenerateUserSystemId(String dialogId, LegitimationInfo legitimationInfo, ClientProductInfo clientProductInfo);
|
||||
|
||||
/**
|
||||
* Gibt die aktuelle Version der Bankparameter Daten zurück
|
||||
*
|
||||
* @return aktuelle Version der Bankparameter Daten
|
||||
*/
|
||||
int getCurrentBpdVersion();
|
||||
|
||||
/**
|
||||
* Zeigt ob die übergebenen BDP Version auch die aktuelle Version ist.
|
||||
*
|
||||
* @param bpdVersion
|
||||
* @return true falls bpdVersion die aktuelle Version ist, ansonsten false.
|
||||
*/
|
||||
boolean isBpdVersionCurrent(int bpdVersion);
|
||||
|
||||
/**
|
||||
* Gibt die aktuelle Version der Userparameter Daten für die übergebene Benutzerkennung zurück
|
||||
*
|
||||
* @param legitimationInfo Benutzerkennung, für die die Version geholt werden soll
|
||||
* @return aktuelle Version der Userparameter Daten
|
||||
*/
|
||||
int getCurrentUpdVersion(LegitimationInfo legitimationInfo);
|
||||
|
||||
/**
|
||||
* Liefert ob übergebene UPD Version auch die aktuelle Version ist.
|
||||
*
|
||||
* @param legitimationInfo Benutzerkennung
|
||||
* @param updVersion updVersion
|
||||
* @return true falls aktuell, ansonsten false.
|
||||
*/
|
||||
boolean isUpdVersionCurrent(LegitimationInfo legitimationInfo, int updVersion);
|
||||
|
||||
/**
|
||||
* Liefert Parameterdaten für die Segmentfolge Bankparameterdaten als Rückmledung auf die Dialoginitilisierung
|
||||
* des Kunden zurück.
|
||||
* <p/>
|
||||
* FinTS 3.0: Formals, D.1
|
||||
*
|
||||
* @param fintsVersion Gibt die FinTS Version an, für die Parameterdaten gefordert wurden
|
||||
* @return Liste mit Parameterdaten für alle erlaubten Geschäftsvorfälle
|
||||
*/
|
||||
ArrayList<ParameterDataObject> getParameterData(FinTSVersionSwitch.FinTSVersion fintsVersion);
|
||||
|
||||
/**
|
||||
* Liefert Bankparameterdaten als Rückmeldung auf die Dialoginitilisierung
|
||||
* des Kunden zurück.
|
||||
* <p/>
|
||||
* FinTS 3.0: Formals, D.2 (HIBPA)
|
||||
*
|
||||
* @param fintsVersion Gibt die FinTS Version an, für die Parameterdaten gefordert wurden
|
||||
* @return BankParameterDaten für die gewählte HBCI Version
|
||||
*/
|
||||
CommonBankParameterDataObject getCommonBankParameters(FinTSVersionSwitch.FinTSVersion fintsVersion);
|
||||
|
||||
/**
|
||||
* Liefert allgemeine Informationen zu den Konten der übergebenen Benutzerkennung zurück
|
||||
* <p/>
|
||||
* FinTS 3.0: Formals, E.1 (HIUPD)
|
||||
*
|
||||
* @param legitimationInfo Legitimationsinfo zum Benutzer
|
||||
* @return AccountDataObject-Liste für alle passenden Konten
|
||||
*/
|
||||
ArrayList<AccountDataObject> getAccountData(LegitimationInfo legitimationInfo);
|
||||
|
||||
/**
|
||||
* Liefert die Parameter die für Pin/Tan benötigt werden.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
PinParameterObject getPinParameter();
|
||||
|
||||
/**
|
||||
* Liefert ob ein Auftrag (aClass repräsentiert das Segment als Klasse) für den
|
||||
* angegebenen Account gültig ist.
|
||||
*
|
||||
* @param legitimationInfo LegitimationInfo
|
||||
* @param accountId die Kontonummer
|
||||
* @param aClass @return
|
||||
*/
|
||||
boolean operationAllowedForAccount(LegitimationInfo legitimationInfo, String accountId, Class<? extends IMessageElement> aClass);
|
||||
|
||||
|
||||
/**
|
||||
* Liefert ob ein Auftrag (aClass repräsentiert das Segment als Klasse) für den
|
||||
* angegebenen Account gültig ist.
|
||||
*
|
||||
* @param legitimationInfo LegitimationInfo
|
||||
* @param aClass @return
|
||||
*/
|
||||
boolean operationAllowedForAccount(LegitimationInfo legitimationInfo, Class<? extends IMessageElement> aClass);
|
||||
|
||||
/**
|
||||
* Liefert den Saldo zu einem angegebenen Account.
|
||||
*
|
||||
* @param accountId
|
||||
* @param legitimationsInfo
|
||||
* @return
|
||||
*/
|
||||
SaldoDataObject getSaldo(String accountId, LegitimationInfo legitimationsInfo);
|
||||
|
||||
/**
|
||||
* Liefert die PIN eines Nutzers für das PIN/TAN verfahren.
|
||||
*
|
||||
* @param userId die ID des Nutzers.
|
||||
* @param pin
|
||||
* @param dialog
|
||||
* @return die PIN des Nutzers oder null.
|
||||
*/
|
||||
ReturnDataObject checkUserPin(String userId, String pin, Dialog dialog);
|
||||
|
||||
/**
|
||||
* Prüft ob eine TAN korrekt ist.
|
||||
*
|
||||
*
|
||||
* @param dialogId
|
||||
* @param legitimationInfo die Kunden-ID
|
||||
* @param clientProductInfo
|
||||
*@param tan die eingegebenen TAN
|
||||
* @param auftragsHashWert der Auftrags-Hashwert @return true falls TAN korrekt, ansonsten false
|
||||
*/
|
||||
ReturnDataObject checkTan(String dialogId, LegitimationInfo legitimationInfo, ClientProductInfo clientProductInfo, String tan, byte[] auftragsHashWert);
|
||||
|
||||
/**
|
||||
* Generiert eine Auftragsreferenz zu einem Auftrag.
|
||||
*
|
||||
* @param dialogId die Dialog-ID
|
||||
* @param clientProductInfo
|
||||
* @param auftragsHashwert der Auftrags-Hashwert @return die generierte Auftragsreferenz
|
||||
*/
|
||||
String generateAuftragsreferenz(String dialogId, LegitimationInfo legitimationInfo, ClientProductInfo clientProductInfo, byte[] auftragsHashwert);
|
||||
|
||||
/**
|
||||
* Liefert die Challenge zu einem Auftrag.
|
||||
*
|
||||
* @param dialogId
|
||||
* @param legitimationInfo BenutzerDaten
|
||||
* @param clientProductInfo KundenProdukt
|
||||
* @param auftragsHashwert der Auftrags-Hashwert
|
||||
* @param tanVerfahren das gewählte TAN verfahren das zur Durchführung genutzt werden soll
|
||||
* @param parameterChallengeKlasse Parameter zur Challenge wie Beispielsweise Beträge oder Kontonummern
|
||||
* @return die Challenge
|
||||
*/
|
||||
ReturnDataObject getChallenge(String dialogId, LegitimationInfo legitimationInfo, ClientProductInfo clientProductInfo, byte[] auftragsHashwert, String tanVerfahren, List<String> parameterChallengeKlasse);
|
||||
|
||||
/**
|
||||
* Reicht eine Inlandsüberweisung ein.
|
||||
*
|
||||
* @param kontoverbindungAuftraggeber die Kontoverbindung des Auftragsgebers
|
||||
* @param kontoverbindungEmpfaenger die Kontoverbindung des Empfänger
|
||||
* @param nameEmpfaenger1 der Name des Empfängers 1
|
||||
* @param nameEmpfaenger2 der Name des Empfängers 2
|
||||
* @param textschluessel der Textschlüssel der Überweisung
|
||||
* @param textschluesselErgaenzung die Textschlüsselergänzung
|
||||
* @param verwendungszweckzeilen die Verwendungszweckzeilen
|
||||
* @param betrag
|
||||
* @param endToEnd
|
||||
* @param purposeCode
|
||||
* @return true falls Auftrag angenommen, ansonsten false
|
||||
*/
|
||||
ReturnDataObject submitNewTransaction(LegitimationInfo legitimationInfo, KontoverbindungNational kontoverbindungAuftraggeber, KontoverbindungNational kontoverbindungEmpfaenger, String nameEmpfaenger1, String nameEmpfaenger2, String textschluessel, String textschluesselErgaenzung, List<String> verwendungszweckzeilen, Betrag betrag, String endToEnd, String purposeCode);
|
||||
|
||||
/**
|
||||
* Reicht eine SEPA-Überweisung ein.
|
||||
*
|
||||
* @param legitimationInfo LegitimationInfo
|
||||
* @param sepaDescriptor Sepa-Bezeichner
|
||||
* @param sepaPainMessage die SEPA-Pain-Message @return true falls Auftrag angenommen, ansonsten false
|
||||
* @param isSammler
|
||||
*/
|
||||
ReturnDataObject submitNewTransaction(LegitimationInfo legitimationInfo, String sepaDescriptor, byte[] sepaPainMessage, boolean isSammler);
|
||||
|
||||
|
||||
/**
|
||||
* Reicht die Pinänderung ein
|
||||
*
|
||||
* @param legitimationInfo LegitimationInfo
|
||||
* @param newPin die Neue PIN, die für den Nutzer hinterlegt werden soll
|
||||
* @return
|
||||
*/
|
||||
ReturnDataObject submitChangePin(LegitimationInfo legitimationInfo, String newPin);
|
||||
|
||||
/**
|
||||
* Liefert die gebuchten Umsätze.
|
||||
*
|
||||
* @param kontonummer die Kontonummer
|
||||
* @param vonDatum ab Datum
|
||||
* @param bisDatum bis Datum
|
||||
* @param legitimationsInfo LegitimationInfo
|
||||
* @return die gebuchten Umsätze als MT940-byte[]
|
||||
*/
|
||||
byte[] getGebuchteUmsaetze(String kontonummer, Date vonDatum, Date bisDatum, LegitimationInfo legitimationsInfo);
|
||||
|
||||
/**
|
||||
* Liefert die nicht-gebuchten Umsätze.
|
||||
*
|
||||
* @param kontonummer die Kontonummer
|
||||
* @param vonDatum ab Datum
|
||||
* @param bisDatum bis Datum
|
||||
* @return die nicht gebuchten Umsätze als MT942-byte[]
|
||||
*/
|
||||
byte[] getNichtGebuchteUmsaetze(String kontonummer, Date vonDatum, Date bisDatum, LegitimationInfo legitimationInfo);
|
||||
|
||||
/**
|
||||
* Liefert die Kontoproduktbezeichnung zu einer Kontonummer.
|
||||
*
|
||||
* @param accountId die Kontonummer
|
||||
* @param legitimationsInfo
|
||||
* @return die Kontoproduktbezeichnung als String.
|
||||
*/
|
||||
String getKontoproduktbezeichnung(String accountId, LegitimationInfo legitimationsInfo);
|
||||
|
||||
/**
|
||||
* Liefert die genutzte Kontowährung zur Kontonummer.
|
||||
*
|
||||
* @param accountId die Kontonummer zu der die Währung abgefragt wird.
|
||||
* @return die verwendete Währung zum Konto.
|
||||
*/
|
||||
String getKontowaehrung(String accountId);
|
||||
|
||||
/**
|
||||
* Prüft ob eine Kunden-ID (customerId) korrekt ist und zur Benutzerkennung (userId) passt.
|
||||
*
|
||||
* @param userId die Benutzerkennung
|
||||
* @param customerId die Kunden-ID
|
||||
* @return true falls die Kunden-ID verifiziert wurde, ansonsten false.
|
||||
*/
|
||||
boolean isCustomerIdValid(String userId, String customerId);
|
||||
|
||||
/**
|
||||
* Liefert alle zugelassen TAN Verfahren für den Konto.
|
||||
*
|
||||
* @param legitimationInfo die LegitimationInfo
|
||||
* @return die zugelassen TAN Verfahren für den Benutzer.
|
||||
*/
|
||||
List<String> getZugelasseneTanVerfahren(LegitimationInfo legitimationInfo);
|
||||
|
||||
/**
|
||||
* @param dialogId die DialogID
|
||||
* @param legitimationInfo die Legitimationsinfo
|
||||
* @param clientProductInfo die Client
|
||||
* @param TAN die zu Entwertende TAN
|
||||
*/
|
||||
void devalueTan(String dialogId, LegitimationInfo legitimationInfo, ClientProductInfo clientProductInfo, String TAN);
|
||||
|
||||
/**
|
||||
* Liefert die Kommunikationsadressen unter der die Banken über HBCI erreichbar sind.
|
||||
*
|
||||
* @param bankId
|
||||
* @return
|
||||
*/
|
||||
KommunikationsParameterData getKommunikationsParameterData(String bankId);
|
||||
|
||||
/**
|
||||
* Funktion für Rückgabe der Bank-Mitteilungen
|
||||
*
|
||||
* @param legitimationInfo die Legitimationsinfo
|
||||
* @param clientProductInfo die ClientProductInfo
|
||||
* @return Liste an Nachrichten
|
||||
*/
|
||||
List<BankMessageObject> getBankMessages(LegitimationInfo legitimationInfo, ClientProductInfo clientProductInfo);
|
||||
|
||||
/**
|
||||
* Liefert den Bestand an an Sepa Einzellastschriften zurück.
|
||||
* In diesem Fall muss im DirectDebitDataObject die SepaPainMessage und der SepaDescriptor gesetzt werden
|
||||
*
|
||||
* @param legitimationInfo die Legitmationsinfo
|
||||
* @return für jede Einzellastschrift ein DirectDebitDataObject in einer Liste
|
||||
*/
|
||||
List<DirectDebitDataObject> getEinzelLastschriftBestand(LegitimationInfo legitimationInfo);
|
||||
|
||||
/**
|
||||
* Liefert den Bestand an an Sepa Sammellastschriften zurück.
|
||||
*
|
||||
* @param legitimationInfo die Legitmationsinfo
|
||||
* @return für jede Einzellastschrift ein DirectDebitDataObject in einer Liste
|
||||
*/
|
||||
List<DirectDebitDataObject> getSammelLastschriftBestand(LegitimationInfo legitimationInfo);
|
||||
|
||||
/**
|
||||
* Kunden haben die Möglichkeit Nachrichten an das Kreditinstitut zu senden.
|
||||
*
|
||||
* @param legitimationsInfo
|
||||
* @param kontoverbindungAuftraggeber kann null sein
|
||||
* @param freitextmeldung
|
||||
* @param betreff kann null sein
|
||||
* @param empfaengerangaben kann null sein
|
||||
* @return true falls die Nachricht angenommen wurden, false andernfalls.
|
||||
*/
|
||||
boolean userMessageSubmitted(LegitimationInfo legitimationsInfo, KontoverbindungNational kontoverbindungAuftraggeber, String freitextmeldung, String betreff, String empfaengerangaben);
|
||||
|
||||
/**
|
||||
* Liefert die BIC des aktuellen Bankinstituts.
|
||||
*
|
||||
* @return die BIC als String.
|
||||
*/
|
||||
String getBic();
|
||||
|
||||
LinkedList<Document> getTerminzahlungen(LegitimationInfo legitimationsInfo, ClientProductInfo clientProductInfo, boolean isSammler, Payments.versions version);
|
||||
|
||||
ReturnDataObject submitNewTransactionSchedule(LegitimationInfo legitimationsInfo, String sepaDescriptor, byte[] sepaFile, boolean isSammler);
|
||||
|
||||
ReturnDataObject deleteTerminzahlung(LegitimationInfo legitimationsInfo, ClientProductInfo clientProductInfo, String auftragsidentifikation, boolean isSammler);
|
||||
|
||||
/**
|
||||
* Liefert die gebuchten SEPA Umsätze.
|
||||
*
|
||||
*
|
||||
* @param kontonummer die Kontonummer
|
||||
* @param vonDatum ab Datum
|
||||
* @param bisDatum bis Datum
|
||||
* @param legitimationsInfo LegitimationInfo
|
||||
* @param camtDescriptor unterstütztes camt Format des Kundenprodukts
|
||||
* @return die gebuchten Umsätze als List<camt.052>
|
||||
*/
|
||||
List<byte[]> getGebuchteCamtUmsaetze(String kontonummer, Date vonDatum, Date bisDatum, LegitimationInfo legitimationsInfo, String camtDescriptor);
|
||||
|
||||
/**
|
||||
* Liefert die nicht-gebuchten SEPA Umsätze.
|
||||
*
|
||||
* @param kontonummer die Kontonummer
|
||||
* @param vonDatum ab Datum
|
||||
* @param bisDatum bis Datum
|
||||
* @return die nicht gebuchten Umsätze als camt.052
|
||||
*/
|
||||
byte[] getNichtGebuchteCamtUmsaetze(String kontonummer, Date vonDatum, Date bisDatum, LegitimationInfo legitimationsInfo);
|
||||
|
||||
/**
|
||||
* Liefert kreditkartenumsätze
|
||||
* @param kreditkartennummer die Nummer der Kreditkarte
|
||||
* @param von Datum ab wann Umsätze geliefert werden sollen
|
||||
* @param bis Datum bis wann Umsätze geliefert werden sollen
|
||||
* @param legitimationsInfo zur Überprüfung
|
||||
* @return Liste von CreditCardRevenueDataObject oder null falls keine Vorhanden sind.
|
||||
*/
|
||||
List<CreditCardRevenueDataObject> getCreditCardRevenueData(String kreditkartennummer, Date von, Date bis, LegitimationInfo legitimationsInfo);
|
||||
|
||||
/**
|
||||
* Liefert den Bestand an Empfängerkonten (für SEPA-Übertrag)
|
||||
* @param legitimationsInfo zur Überprüfung
|
||||
* @param kontoverbindungInternational Konto für das der Bestand zurückgeliefert werden soll
|
||||
* @return Liste mit den Empfängerkonten-Daten oder null falls keine Vorhanden sind.
|
||||
*/
|
||||
List<RecipientAccountDataObject> getEmpfaengerkontenbestand(LegitimationInfo legitimationsInfo, KontoverbindungInternational kontoverbindungInternational);
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package net.petafuel.fuelifints.dataaccess;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class DataAccessFacadeManager {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(DataAccessFacadeManager.class);
|
||||
private static final ConcurrentHashMap<String, DataAccessFacade> accessFacadeHashMap = new ConcurrentHashMap<>();
|
||||
|
||||
private static final String CLASS_DEBUG = "net.petafuel.fuelifints.dataaccess.DummyAccessFacade";
|
||||
private static final String CLASS_PREPAID = "net.petafuel.fuelifints.dataaccess.PrepaidAccess";
|
||||
private static final String CLASS_BANKING2 = "net.petafuel.fuelifints.dataaccess.Banking2Access";
|
||||
|
||||
/**
|
||||
* Diese Funktion liefert zur übergebenen Bankleitzahl die passende Dataaccessfacade zurück.
|
||||
* Dafür wird die entsprechende Properties Datei aus dem Dateisystem ausgelesen.
|
||||
* Die Properties Datei befindet sich im Verzeichnis ./config/ und hat das Format
|
||||
* <BLZ>.<FACADEIMPL>.properties
|
||||
* Sollte keine passende Configdatei gefunden werden, liefert diese Funktion null zurück
|
||||
* <p/>
|
||||
* Die DataAccessFacade wird dabei gespeichert, es wird also pro Bankleitzahl immer nur eine DataAccessFacade instanziert
|
||||
*
|
||||
* @param bankId Bankleitzahl, für die eine DataAccessFacade benötigt wird
|
||||
* @return DataAccessFacade oder null
|
||||
*/
|
||||
public static DataAccessFacade getAccessFacade(String bankId) {
|
||||
try {
|
||||
|
||||
final String banking2properties = "config/" + bankId + ".banking2.properties";
|
||||
final String prepaidProperties = "config/" + bankId + ".prepaid.properties";
|
||||
final String dummyProperties = "config/" + bankId + ".dummy.properties";
|
||||
|
||||
if (new File(banking2properties).exists()) {
|
||||
LOG.info("Banking2-config gefunden: {}", banking2properties);
|
||||
if (!accessFacadeHashMap.containsKey(bankId)) {
|
||||
accessFacadeHashMap.put(bankId, instantiateNewFacade(CLASS_BANKING2, banking2properties));
|
||||
}
|
||||
} else {
|
||||
if (new File(prepaidProperties).exists()) {
|
||||
LOG.info("Prepaid-config gefunden: {}", prepaidProperties);
|
||||
if (!accessFacadeHashMap.containsKey(bankId)) {
|
||||
accessFacadeHashMap.put(bankId, instantiateNewFacade(CLASS_PREPAID, prepaidProperties));
|
||||
}
|
||||
} else {
|
||||
if (new File(dummyProperties).exists() || bankId.equals("DEBUG")) {
|
||||
LOG.info("Dummy-config gefunden: {} ...(oder DEBUG BankID)", dummyProperties);
|
||||
if (!accessFacadeHashMap.containsKey(bankId)) {
|
||||
accessFacadeHashMap.put(bankId, instantiateNewFacade(CLASS_DEBUG, dummyProperties));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Cannot DataAccessFacade#getAccessFacade for bankId={}", bankId, e);
|
||||
}
|
||||
|
||||
DataAccessFacade dataAccessFacade = accessFacadeHashMap.get(bankId);
|
||||
LOG.info("BankCode={}, DataAccessFacade={} ", bankId, dataAccessFacade);
|
||||
|
||||
return dataAccessFacade;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static DataAccessFacade instantiateNewFacade(String classPath, String configPath) {
|
||||
try {
|
||||
Class facadeClass = Class.forName(classPath);
|
||||
Class[] constructorParamClasses = new Class[]{String.class};
|
||||
Object[] constructorParamValues = new Object[]{configPath};
|
||||
Constructor constructor = facadeClass.getConstructor(constructorParamClasses);
|
||||
return (DataAccessFacade) constructor.newInstance(constructorParamValues);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Cannot instantiateNewFacade! classPath={}, configPath={}", classPath, configPath, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package net.petafuel.fuelifints.dataaccess;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class SqlConnectionPool {
|
||||
private static final Logger LOG = LogManager.getLogger(SqlConnectionPool.class);
|
||||
private final Hashtable<Connection, Boolean> connections = new Hashtable<>();
|
||||
|
||||
|
||||
public synchronized Connection getConnection() throws SQLException {
|
||||
Connection con;
|
||||
Enumeration<Connection> cons = connections.keys();
|
||||
|
||||
synchronized (connections) {
|
||||
while (cons.hasMoreElements()) {
|
||||
con = cons.nextElement();
|
||||
Boolean b = connections.get(con);
|
||||
if (b == Boolean.FALSE) {
|
||||
// So we found an unused connection.
|
||||
// Test its integrity with a quick setAutoCommit(true) call.
|
||||
// For production use, more testing should be performed,
|
||||
// such as executing a simple query.
|
||||
try {
|
||||
con.setAutoCommit(true);
|
||||
} catch (SQLException e) {
|
||||
// Problem with the connection, replace it.
|
||||
connections.remove(con);
|
||||
con = createNew();
|
||||
}
|
||||
// Update the Hashtable to show this one's taken
|
||||
connections.put(con, Boolean.TRUE);
|
||||
// Return the connection
|
||||
return con;
|
||||
}
|
||||
}
|
||||
// If we get here, there were no free connections. Make one more.
|
||||
// A more robust connection pool would have a maximum size limit,
|
||||
// and would reclaim connections after some timeout period
|
||||
con = createNew();
|
||||
connections.put(con, Boolean.TRUE);
|
||||
return con;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void putBack(Connection returned) {
|
||||
if (returned != null && connections.containsKey(returned)) {
|
||||
connections.put(returned, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
protected Connection createNew() throws SQLException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
/**
|
||||
* Enthält Daten zu den Konten eines Kunden
|
||||
* <p/>
|
||||
* FinTS 3.0: Diese Daten werden im Segment HIUPD verwendet
|
||||
*/
|
||||
public class AccountDataObject implements IDataObject {
|
||||
|
||||
private String kontonummer;
|
||||
|
||||
private String bankleitzahl;
|
||||
|
||||
private String kunden_id;
|
||||
|
||||
private String kontoart;
|
||||
|
||||
private String kontowaehrung;
|
||||
|
||||
private String name;
|
||||
|
||||
private String produktbzeichnung;
|
||||
|
||||
private String kontolimit;
|
||||
|
||||
private String erlaubteGeschaeftsvorfaelle;
|
||||
|
||||
public AccountDataObject(String kontonummer, String bankleitzahl, String name, String produktbzeichnung) {
|
||||
this.kontonummer = kontonummer;
|
||||
this.bankleitzahl = bankleitzahl;
|
||||
this.name = name;
|
||||
this.produktbzeichnung = produktbzeichnung;
|
||||
}
|
||||
|
||||
public String getKontonummer() {
|
||||
return kontonummer;
|
||||
}
|
||||
|
||||
public void setKontonummer(String kontonummer) {
|
||||
this.kontonummer = kontonummer;
|
||||
}
|
||||
|
||||
public String getBankleitzahl() {
|
||||
return bankleitzahl;
|
||||
}
|
||||
|
||||
public void setBankleitzahl(String bankleitzahl) {
|
||||
this.bankleitzahl = bankleitzahl;
|
||||
}
|
||||
|
||||
public String getKunden_id() {
|
||||
return kunden_id;
|
||||
}
|
||||
|
||||
public void setKunden_id(String kunden_id) {
|
||||
this.kunden_id = kunden_id;
|
||||
}
|
||||
|
||||
public String getKontoart() {
|
||||
return kontoart;
|
||||
}
|
||||
|
||||
public void setKontoart(String kontoart) {
|
||||
this.kontoart = kontoart;
|
||||
}
|
||||
|
||||
public String getKontowaehrung() {
|
||||
return kontowaehrung;
|
||||
}
|
||||
|
||||
public void setKontowaehrung(String kontowaehrung) {
|
||||
this.kontowaehrung = kontowaehrung;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getProduktbzeichnung() {
|
||||
return produktbzeichnung;
|
||||
}
|
||||
|
||||
public void setProduktbzeichnung(String produktbzeichnung) {
|
||||
this.produktbzeichnung = produktbzeichnung;
|
||||
}
|
||||
|
||||
public String getKontolimit() {
|
||||
return kontolimit;
|
||||
}
|
||||
|
||||
public void setKontolimit(String kontolimit) {
|
||||
this.kontolimit = kontolimit;
|
||||
}
|
||||
|
||||
public String getErlaubteGeschaeftsvorfaelle() {
|
||||
return erlaubteGeschaeftsvorfaelle;
|
||||
}
|
||||
|
||||
public void setErlaubteGeschaeftsvorfaelle(String erlaubteGeschaeftsvorfaelle) {
|
||||
this.erlaubteGeschaeftsvorfaelle = erlaubteGeschaeftsvorfaelle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AccountDataObject{" +
|
||||
"kontonummer='" + kontonummer + '\'' +
|
||||
", bankleitzahl='" + bankleitzahl + '\'' +
|
||||
", kunden_id='" + kunden_id + '\'' +
|
||||
", kontoart='" + kontoart + '\'' +
|
||||
", kontowaehrung='" + kontowaehrung + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", produktbzeichnung='" + produktbzeichnung + '\'' +
|
||||
", kontolimit='" + kontolimit + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
public class BankMessageObject
|
||||
{
|
||||
private String subject;
|
||||
private String message;
|
||||
public BankMessageObject(String subject,String message)
|
||||
{
|
||||
this.subject = (subject != null) ? subject : "";
|
||||
this.message = (message != null) ? message : "";
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getSubject()
|
||||
{
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
/**
|
||||
* Allgemeine Bankparameter
|
||||
*
|
||||
* FinTS 3.0: Informationen aus Segment HIBPA
|
||||
*/
|
||||
public class CommonBankParameterDataObject implements IDataObject {
|
||||
|
||||
private int bpd_version;
|
||||
|
||||
private String bankleitzahl;
|
||||
|
||||
private String kreditinstitutsbezeichnung;
|
||||
|
||||
private String unterstuetzte_Sprachen;
|
||||
|
||||
private String unterstuetzte_hbci_versionen;
|
||||
|
||||
private Integer maximale_nachrichten_groesse;
|
||||
|
||||
private Integer minimaler_timeout_wert;
|
||||
|
||||
private Integer maximaler_timeout_wert;
|
||||
|
||||
public CommonBankParameterDataObject(int bpd_version, String bankleitzahl, String kreditinstitutsbezeichnung, String unterstuetzte_Sprachen, String unterstuetzte_hbci_versionen) {
|
||||
this.bpd_version = bpd_version;
|
||||
this.bankleitzahl = bankleitzahl;
|
||||
this.kreditinstitutsbezeichnung = kreditinstitutsbezeichnung;
|
||||
this.unterstuetzte_Sprachen = unterstuetzte_Sprachen;
|
||||
this.unterstuetzte_hbci_versionen = unterstuetzte_hbci_versionen;
|
||||
}
|
||||
|
||||
public int getBpd_version() {
|
||||
return bpd_version;
|
||||
}
|
||||
|
||||
public void setBpd_version(int bpd_version) {
|
||||
this.bpd_version = bpd_version;
|
||||
}
|
||||
|
||||
public String getKreditinstitutsbezeichnung() {
|
||||
return kreditinstitutsbezeichnung;
|
||||
}
|
||||
|
||||
|
||||
public void setKreditinstitutsbezeichnung(String kreditinstitutsbezeichnung) {
|
||||
this.kreditinstitutsbezeichnung = kreditinstitutsbezeichnung;
|
||||
}
|
||||
|
||||
public String getUnterstuetzte_Sprachen() {
|
||||
return unterstuetzte_Sprachen;
|
||||
}
|
||||
|
||||
public void setUnterstuetzte_Sprachen(String unterstuetzte_Sprachen) {
|
||||
this.unterstuetzte_Sprachen = unterstuetzte_Sprachen;
|
||||
}
|
||||
|
||||
public String getUnterstuetzte_hbci_versionen() {
|
||||
return unterstuetzte_hbci_versionen;
|
||||
}
|
||||
|
||||
public void setUnterstuetzte_hbci_versionen(String unterstuetzte_hbci_versionen) {
|
||||
this.unterstuetzte_hbci_versionen = unterstuetzte_hbci_versionen;
|
||||
}
|
||||
|
||||
public Integer getMaximale_nachrichten_groesse() {
|
||||
return maximale_nachrichten_groesse;
|
||||
}
|
||||
|
||||
public void setMaximale_nachrichten_groesse(Integer maximale_nachrichten_groesse) {
|
||||
this.maximale_nachrichten_groesse = maximale_nachrichten_groesse;
|
||||
}
|
||||
|
||||
public Integer getMinimaler_timeout_wert() {
|
||||
return minimaler_timeout_wert;
|
||||
}
|
||||
|
||||
public void setMinimaler_timeout_wert(Integer minimaler_timeout_wert) {
|
||||
this.minimaler_timeout_wert = minimaler_timeout_wert;
|
||||
}
|
||||
|
||||
public Integer getMaximaler_timeout_wert() {
|
||||
return maximaler_timeout_wert;
|
||||
}
|
||||
|
||||
public void setMaximaler_timeout_wert(Integer maximaler_timeout_wert) {
|
||||
this.maximaler_timeout_wert = maximaler_timeout_wert;
|
||||
}
|
||||
|
||||
public String getBankleitzahl() {
|
||||
return bankleitzahl;
|
||||
}
|
||||
|
||||
public void setBankleitzahl(String bankleitzahl) {
|
||||
this.bankleitzahl = bankleitzahl;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class CreditCardRevenueDataObject {
|
||||
|
||||
private String creditCardNumber;
|
||||
private Date voucherDate;
|
||||
private Date bookingDate;
|
||||
private double amount;
|
||||
private String purpose;
|
||||
private boolean billed;
|
||||
|
||||
public String getCreditCardNumber() {
|
||||
return creditCardNumber;
|
||||
}
|
||||
|
||||
public void setCreditCardNumber(String creditCardNumber) {
|
||||
this.creditCardNumber = creditCardNumber;
|
||||
}
|
||||
|
||||
public Date getVoucherDate() {
|
||||
return voucherDate;
|
||||
}
|
||||
|
||||
public void setVoucherDate(Date voucherDate) {
|
||||
this.voucherDate = voucherDate;
|
||||
}
|
||||
|
||||
public void setBookingDate(Date bookingDate) {
|
||||
this.bookingDate = bookingDate;
|
||||
}
|
||||
|
||||
public Date getBookingDate() {
|
||||
return bookingDate;
|
||||
}
|
||||
|
||||
public void setPurpose(String purpose) {
|
||||
this.purpose = purpose;
|
||||
}
|
||||
|
||||
public double getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(double amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getPurpose() {
|
||||
return purpose;
|
||||
}
|
||||
|
||||
|
||||
public boolean isBilled() {
|
||||
return billed;
|
||||
}
|
||||
|
||||
public void setBilled(boolean billed) {
|
||||
this.billed = billed;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Objekt für die Rückmeldung von Lastschrift Beständen
|
||||
*/
|
||||
public class DirectDebitDataObject implements IDataObject {
|
||||
|
||||
private String auftragsIdentifikation; //Genutzt im Einzel- und Sammellastschrift-Bestand
|
||||
|
||||
private Date einreichungsdatum; //Genutzt im Sammellastschrift-Bestand
|
||||
|
||||
private Date ausfuehrungsDatum; //Genutzt im Sammellastschrift-Bestand
|
||||
|
||||
private Integer anzahlDerAuftraege; //Genutzt im Sammellastschrift-Bestand
|
||||
|
||||
private Double summeDerBetraege; //Genutzt im Sammellastschrift-Bestand
|
||||
|
||||
private String sepaPainMessage; //Genutzt im Einzellastschrift-Bestand
|
||||
|
||||
private String sepaDescriptor; //Genutzt im Einzellastschrift-Bestand
|
||||
|
||||
public String getAuftragsIdentifikation() {
|
||||
return auftragsIdentifikation;
|
||||
}
|
||||
|
||||
public void setAuftragsIdentifikation(String auftragsIdentifikation) {
|
||||
this.auftragsIdentifikation = auftragsIdentifikation;
|
||||
}
|
||||
|
||||
public Date getEinreichungsdatum() {
|
||||
return einreichungsdatum;
|
||||
}
|
||||
|
||||
public void setEinreichungsdatum(Date einreichungsdatum) {
|
||||
this.einreichungsdatum = einreichungsdatum;
|
||||
}
|
||||
|
||||
public Date getAusfuehrungsDatum() {
|
||||
return ausfuehrungsDatum;
|
||||
}
|
||||
|
||||
public void setAusfuehrungsDatum(Date ausfuehrungsDatum) {
|
||||
this.ausfuehrungsDatum = ausfuehrungsDatum;
|
||||
}
|
||||
|
||||
public Integer getAnzahlDerAuftraege() {
|
||||
return anzahlDerAuftraege;
|
||||
}
|
||||
|
||||
public void setAnzahlDerAuftraege(Integer anzahlDerAuftraege) {
|
||||
this.anzahlDerAuftraege = anzahlDerAuftraege;
|
||||
}
|
||||
|
||||
public Double getSummeDerBetraege() {
|
||||
return summeDerBetraege;
|
||||
}
|
||||
|
||||
public void setSummeDerBetraege(Double summeDerBetraege) {
|
||||
this.summeDerBetraege = summeDerBetraege;
|
||||
}
|
||||
|
||||
public String getSepaPainMessage() {
|
||||
return sepaPainMessage;
|
||||
}
|
||||
|
||||
public void setSepaPainMessage(String sepaPainMessage) {
|
||||
this.sepaPainMessage = sepaPainMessage;
|
||||
}
|
||||
|
||||
public String getSepaDescriptor() {
|
||||
return sepaDescriptor;
|
||||
}
|
||||
|
||||
public void setSepaDescriptor(String sepaDescriptor) {
|
||||
this.sepaDescriptor = sepaDescriptor;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
import net.petafuel.jsepa.util.BankDateCalculator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
public class HolidaysObject {
|
||||
private static final Logger LOG = LogManager.getLogger(HolidaysObject.class);
|
||||
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ls_art core1 specific
|
||||
* @param ls_sequenz core1 specific
|
||||
* @param sepaDueDate DueDate of the SDD
|
||||
* @param cutOffHour Time of day when the cutOff is reached
|
||||
* @param cutOffMinutes Time of day when the cutOff is reached
|
||||
* @param cutOffAdditionalDays Days to add after the cutOff Time is reached for the specific Bank
|
||||
* @param sddDueDateAdditionalDays Days to always add to the Due Date of SEPA Direct Debit Transactions
|
||||
* @param checkCore1 is the direct debit of type core1
|
||||
* @return Date
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public static Date checkDueDate(String ls_art, String ls_sequenz, Date sepaDueDate, int cutOffHour, int cutOffMinutes, int cutOffAdditionalDays, int sddDueDateAdditionalDays, boolean checkCore1) throws UnsupportedOperationException
|
||||
{
|
||||
// Calculate target executiondate and compare with xml executiondate:
|
||||
Calendar cutOffTime = new GregorianCalendar();
|
||||
cutOffTime.set(Calendar.HOUR_OF_DAY, cutOffHour);
|
||||
cutOffTime.set(Calendar.MINUTE, cutOffMinutes);
|
||||
|
||||
Calendar todayTime = new GregorianCalendar();
|
||||
if (todayTime.after(cutOffTime)) {
|
||||
//if the cutoff time is reached, add the additional cutoff days
|
||||
sddDueDateAdditionalDays += cutOffAdditionalDays;
|
||||
}
|
||||
if (checkCore1) {
|
||||
try {
|
||||
sddDueDateAdditionalDays += BankDateCalculator.getAdditionalDayCount(ls_art, ls_sequenz);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Ungültige SEPA-Lastschrift-Art oder -Sequenz");
|
||||
throw new UnsupportedOperationException("Ungültige SEPA-Lastschrift-Art oder -Sequenz");
|
||||
}
|
||||
} else {
|
||||
// Always add one day as SDD is to be inquired to the bank at least one day in advance
|
||||
sddDueDateAdditionalDays++;
|
||||
}
|
||||
Calendar targetExecutionTime = BankDateCalculator.getTarget2DiffDate(sddDueDateAdditionalDays);
|
||||
//Change Calender.HOUR_OF_DAY to ensure sepaDueDate is after targetExecutionTime if both have the same date, but differ in time
|
||||
targetExecutionTime.set(Calendar.HOUR_OF_DAY, 0);
|
||||
targetExecutionTime.set(Calendar.MINUTE, 0);
|
||||
targetExecutionTime.set(Calendar.SECOND, 0);
|
||||
Calendar executionTime = new GregorianCalendar();
|
||||
executionTime.setTime(sepaDueDate);
|
||||
executionTime.set(Calendar.HOUR_OF_DAY, 0);
|
||||
executionTime.set(Calendar.MINUTE, 0);
|
||||
executionTime.set(Calendar.SECOND, 1);
|
||||
GregorianCalendar maxExecutionTime = new GregorianCalendar();
|
||||
maxExecutionTime.setTime(new Date());
|
||||
maxExecutionTime.set(Calendar.HOUR_OF_DAY, 0);
|
||||
maxExecutionTime.set(Calendar.MINUTE, 0);
|
||||
maxExecutionTime.set(Calendar.SECOND, 1);
|
||||
maxExecutionTime.add(Calendar.DAY_OF_YEAR, 14);
|
||||
LOG.info("Days to add: {}, TargetExecutionTime: {}, ExecutionTime: {}, MaxExecutionTime: {}", sddDueDateAdditionalDays, sdf.format(targetExecutionTime.getTime()), sdf.format(executionTime.getTime()), sdf.format(maxExecutionTime.getTime()));
|
||||
if (!(executionTime.getTime().after(targetExecutionTime.getTime()))) {
|
||||
LOG.warn("Zeitraum für Mindestvorlaufzeit stimmt nicht");
|
||||
throw new UnsupportedOperationException("Zeitraum fuer Mindestvorlaufzeit stimmt nicht");
|
||||
}
|
||||
if (!(executionTime.getTime().before(maxExecutionTime.getTime()))) {
|
||||
LOG.warn("Zeitraum von maximal 2 Wochen wurde nicht eingehalten");
|
||||
throw new UnsupportedOperationException("Zeitraum von maximal 2 Wochen wurde nicht eingehalten");
|
||||
}
|
||||
return sepaDueDate;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
public interface IDataObject {
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class KommunikationsParameterData {
|
||||
private String bankId;
|
||||
private List<String> kommunikationszugaenge;
|
||||
|
||||
public String getBankId() {
|
||||
return bankId;
|
||||
}
|
||||
|
||||
public void setBankId(String bankId) {
|
||||
this.bankId = bankId;
|
||||
}
|
||||
|
||||
public List<String> getKommunikationszugangsAdressen() {
|
||||
return kommunikationszugaenge;
|
||||
}
|
||||
|
||||
public void setKommunikationszugaenge(List<String> kommunikationszugaenge) {
|
||||
this.kommunikationszugaenge = kommunikationszugaenge;
|
||||
}
|
||||
|
||||
public void addKommunikationszugang(String zugangsAdresse) {
|
||||
if (kommunikationszugaenge == null) {
|
||||
kommunikationszugaenge = new LinkedList<>();
|
||||
}
|
||||
kommunikationszugaenge.add(zugangsAdresse);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Klasse, um Parameterdaten aus den entsprechenden Facade Implementierungen zurückzugeben
|
||||
* <p/>
|
||||
* FinTS 3.0: Siehe Formals, D.1
|
||||
*/
|
||||
public class ParameterDataObject implements IDataObject {
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterDataObject.class);
|
||||
|
||||
private String segmentName;
|
||||
|
||||
private int segmentVersion;
|
||||
|
||||
private int maximaleAnzahlAuftraege;
|
||||
|
||||
private Integer anzahlSignaturenMindestens;
|
||||
|
||||
private String sicherheitsKlasse;
|
||||
|
||||
private String parameter;
|
||||
|
||||
public ParameterDataObject(String segmentName, int segmentVersion, int maximaleAnzahlAuftraege, int anzahlSignaturenMindestens, String sicherheitsKlasse, String parameter) {
|
||||
this.segmentName = segmentName;
|
||||
this.segmentVersion = segmentVersion;
|
||||
this.maximaleAnzahlAuftraege = maximaleAnzahlAuftraege;
|
||||
LOG.debug("Anzahl signaturen mindestens: {} {}", anzahlSignaturenMindestens, (anzahlSignaturenMindestens < 0));
|
||||
this.anzahlSignaturenMindestens = anzahlSignaturenMindestens < 0 ? null : anzahlSignaturenMindestens;
|
||||
this.sicherheitsKlasse = sicherheitsKlasse;
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public Integer getAnzahlSignaturenMindestens() {
|
||||
return anzahlSignaturenMindestens;
|
||||
}
|
||||
|
||||
public void setAnzahlSignaturenMindestens(int anzahlSignaturenMindestens) {
|
||||
this.anzahlSignaturenMindestens = anzahlSignaturenMindestens;
|
||||
}
|
||||
|
||||
public int getMaximaleAnzahlAuftraege() {
|
||||
return maximaleAnzahlAuftraege;
|
||||
}
|
||||
|
||||
public void setMaximaleAnzahlAuftraege(int maximaleAnzahlAuftraege) {
|
||||
this.maximaleAnzahlAuftraege = maximaleAnzahlAuftraege;
|
||||
}
|
||||
|
||||
|
||||
public int getSegmentVersion() {
|
||||
return segmentVersion;
|
||||
}
|
||||
|
||||
public void setSegmentVersion(int segmentVersion) {
|
||||
this.segmentVersion = segmentVersion;
|
||||
}
|
||||
|
||||
public String getSegmentName() {
|
||||
return segmentName;
|
||||
}
|
||||
|
||||
public void setSegmentName(String segmentName) {
|
||||
this.segmentName = segmentName;
|
||||
}
|
||||
|
||||
public String getSicherheitsKlasse() {
|
||||
return sicherheitsKlasse;
|
||||
}
|
||||
|
||||
public void setSicherheitsKlasse(String sicherheitsKlasse) {
|
||||
this.sicherheitsKlasse = sicherheitsKlasse;
|
||||
}
|
||||
|
||||
public String getParameter() {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public void setParameter(String parameter) {
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParameterDataObject{" +
|
||||
"segmentName='" + segmentName + '\'' +
|
||||
", segmentVersion=" + segmentVersion +
|
||||
", maximaleAnzahlAuftraege=" + maximaleAnzahlAuftraege +
|
||||
", anzahlSignaturenMindestens=" + anzahlSignaturenMindestens +
|
||||
", sicherheitsKlasse='" + sicherheitsKlasse + '\'' +
|
||||
", parameter='" + parameter + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
import net.petafuel.fuelifints.FinTSVersionSwitch;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class PermissionDataObject
|
||||
{
|
||||
public static final String verfahren_iTan = "912";
|
||||
public static final String verfahren_mTan = "913";
|
||||
public static final String verfahren_iTanSms = "914";
|
||||
private static List<GlobalParameter> bankParameters = null;
|
||||
/**
|
||||
* Liste aller Geschäftsvorfälle (auch nicht aktive)
|
||||
*/
|
||||
private static HashMap<FINTS30, String> geschaeftsvorfaelle = new HashMap<FINTS30, String>()
|
||||
{{
|
||||
put(FINTS30.SaldoAbfrage, "HKSAL");
|
||||
put(FINTS30.UmsatzAbfrage, "HKKAZ");
|
||||
put(FINTS30.PinTanVerfahren, "HKTAN");
|
||||
put(FINTS30.PinAendern, "HKPAE");
|
||||
put(FINTS30.SepaKontoVerbindungen, "HKSPA");
|
||||
put(FINTS30.SepaUeberweisungEinzelEinreichen, "HKCCS");
|
||||
put(FINTS30.SepaUeberweisungSammelEinreichen, "HKCCM");
|
||||
put(FINTS30.PinTanZweiSchrittParameter, "HKTAB");
|
||||
put(FINTS30.SepaLastschriftEinzelEinreichenCore1, "HKDSC");
|
||||
put(FINTS30.SepaLastschriftEinzelEinreichenB2B,"HKBSE");
|
||||
put(FINTS30.SepaLastschriftEinzelEinreichen, "HKDSE");
|
||||
put(FINTS30.SepaLastschriftEinzelAendern, "HKDSL");
|
||||
put(FINTS30.SepaLastschriftEinzelLoeschen, "HKDSA");
|
||||
put(FINTS30.SepaLastschriftEinzelLoeschenB2B,"HKBSL");
|
||||
put(FINTS30.SepaLastschriftEinzelBestand, "HKDBS");
|
||||
put(FINTS30.SepaLastschriftEinzelBestandB2B,"HKBBS");
|
||||
put(FINTS30.SepaLastschriftSammelEinreichenCore1,"HKDMC");
|
||||
put(FINTS30.SepaLastschriftSammelEinreichenB2B, "HKBME");
|
||||
put(FINTS30.SepaLastschriftSammelEinreichen, "HKDME");
|
||||
put(FINTS30.SepaLastschriftSammelBestand, "HKDMB");
|
||||
put(FINTS30.SepaLastschriftSammelBestandB2B, "HKBMB");
|
||||
put(FINTS30.SepaLastschriftSammelLoeschen, "HKDML");
|
||||
put(FINTS30.SepaLastschriftSammelLoeschenB2B, "HKBML");
|
||||
put(FINTS30.KundenBankNachricht,"HKKDM");
|
||||
put(FINTS30.Vormerkumsaetze,"HKVMK");
|
||||
put(FINTS30.SepaUeberweisungEinzelTerminEinreichen,"HKCSE");
|
||||
put(FINTS30.SepaUeberweisungEinzelTerminBestand,"HKCSB");
|
||||
put(FINTS30.SepaUeberweisungEinzelTerminLoeschen,"HKCSL");
|
||||
put(FINTS30.SepaUeberweisungSammelTerminEinreichen,"HKCME");
|
||||
put(FINTS30.SepaUeberweisungSammelTerminBestand,"HKCMB");
|
||||
put(FINTS30.SepaUeberweisungSammelTerminLoeschen, "HKMSL");
|
||||
put(FINTS30.Identifikation, "HKIDN");
|
||||
}};
|
||||
|
||||
private static HashMap<FINTS30, Boolean> pinRequired = null;
|
||||
private String permissions = "";
|
||||
|
||||
/**
|
||||
* Liste der aktiven Geschäftsvorfälle
|
||||
* @return FINTS30-Liste
|
||||
*/
|
||||
public static List<FINTS30> getAllowedFINTS30()
|
||||
{
|
||||
return Arrays.asList(
|
||||
FINTS30.SaldoAbfrage,
|
||||
FINTS30.UmsatzAbfrage,
|
||||
FINTS30.PinTanVerfahren,
|
||||
FINTS30.PinTanZweiSchrittParameter,
|
||||
FINTS30.SepaKontoVerbindungen,
|
||||
FINTS30.SepaUeberweisungEinzelEinreichen,
|
||||
FINTS30.SepaUeberweisungEinzelTerminEinreichen,
|
||||
FINTS30.SepaUeberweisungEinzelTerminBestand,
|
||||
FINTS30.SepaUeberweisungEinzelTerminLoeschen,
|
||||
FINTS30.SepaUeberweisungSammelEinreichen,
|
||||
FINTS30.SepaUeberweisungSammelTerminEinreichen,
|
||||
FINTS30.SepaUeberweisungSammelTerminBestand,
|
||||
FINTS30.SepaUeberweisungSammelTerminLoeschen,
|
||||
FINTS30.SepaLastschriftEinzelEinreichen,
|
||||
FINTS30.SepaLastschriftEinzelEinreichenCore1,
|
||||
FINTS30.SepaLastschriftEinzelEinreichenB2B,
|
||||
FINTS30.SepaLastschriftEinzelLoeschen,
|
||||
FINTS30.SepaLastschriftEinzelLoeschenB2B,
|
||||
FINTS30.SepaLastschriftEinzelAendern,
|
||||
FINTS30.SepaLastschriftEinzelBestand,
|
||||
FINTS30.SepaLastschriftEinzelBestandB2B,
|
||||
FINTS30.SepaLastschriftSammelEinreichen,
|
||||
FINTS30.SepaLastschriftSammelEinreichenCore1,
|
||||
FINTS30.SepaLastschriftSammelEinreichenB2B,
|
||||
FINTS30.SepaLastschriftSammelLoeschen,
|
||||
FINTS30.SepaLastschriftSammelLoeschenB2B,
|
||||
FINTS30.SepaLastschriftSammelBestand,
|
||||
FINTS30.SepaLastschriftSammelBestandB2B,
|
||||
FINTS30.PinAendern,
|
||||
FINTS30.KundenBankNachricht,
|
||||
FINTS30.Vormerkumsaetze
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste mit HBCI-ParameterObjekten
|
||||
* @return Liste
|
||||
*/
|
||||
public static List<GlobalParameter> getBankParameters()
|
||||
{
|
||||
if (bankParameters == null)
|
||||
{
|
||||
TanProcessParameterObject iTAN = getiTanParameter();
|
||||
TanProcessParameterObject mTAN = getmTanParameter();
|
||||
TanProcessParameterObject iTANsms = getiTanSmsParameter();
|
||||
bankParameters = new ArrayList<>();
|
||||
bankParameters.add(new GlobalParameter("HICCMS", 1, 10, "1", "1", "1000:J:J", "")); // Sammel Einreichung
|
||||
bankParameters.add(new GlobalParameter("HICCSS", 1, 1, "1", "2", "", "")); // Einzel Einreichung
|
||||
//2 SEPA-Einzel-Lastschriften
|
||||
bankParameters.add(new GlobalParameter("HIDSES", 1, 1, "1", "1", "1:14:1:14", "")); // Einreichen
|
||||
bankParameters.add(new GlobalParameter("HIDSCS", 1, 1, "1", "1", "1:14:1:14", "")); // COR1 Einreichen
|
||||
bankParameters.add(new GlobalParameter("HIDBSS", 1, 1, "1", "1", "J:N", "")); // Bestand
|
||||
bankParameters.add(new GlobalParameter("HIDBSS", 1, 1, "1", "1", "J:N", "")); // Änderung
|
||||
bankParameters.add(new GlobalParameter("HIDSAS", 1, 1, "1", "1", "1:14:1:14", "")); // Löschen
|
||||
bankParameters.add(new GlobalParameter("HIDSLS", 1, 1, "1", "1", "J", ""));
|
||||
//7 SEPA-Sammel-Lastschriften
|
||||
bankParameters.add(new GlobalParameter("HIDMES", 1, 1, "1", "1", "1:14:1:14:1000:N:J", ""));// Einreichung
|
||||
bankParameters.add(new GlobalParameter("HIDMCS", 1, 1, "1", "1", "100:N:N:1:14:1:14", ""));// COR1 Einreichen
|
||||
bankParameters.add(new GlobalParameter("HIDMBS", 1, 1, "1", "1", "N:N", "")); // Bestand
|
||||
bankParameters.add(new GlobalParameter("HIDMLS", 1, 1, "1", "1", "", "")); // Löschung
|
||||
//11 Umsätze abrufen
|
||||
bankParameters.add(new GlobalParameter("HIKAZS", 6, 1, "1", "1", "90:J:J", ""));
|
||||
bankParameters.add(new GlobalParameter("HIKAZS", 7, 1, "1", "1", "90:J:J", ""));
|
||||
bankParameters.add(new GlobalParameter("HIKAZS", 5, 1, "1", "", "90:J:N", ""));
|
||||
//14 Saldo abrufen
|
||||
bankParameters.add(new GlobalParameter("HISALS", 5, 1, "1", "", "", ""));
|
||||
bankParameters.add(new GlobalParameter("HISALS", 6, 1, "1", "1", "", ""));
|
||||
bankParameters.add(new GlobalParameter("HISALS", 7, 1, "1", "1", "", ""));
|
||||
//17 SEPA-Parameter
|
||||
bankParameters.add(new GlobalParameter("HISPAS", 1, 1, "1", "1", "J:N:N:sepade.pain.001.001.02.xsd:sepade.pain.001.002.02.xsd:sepade.pain.001.001.03.xsd:sepade.pain.001.002.03.xsd:sepade.pain.008.001.02.xsd:sepade.pain.008.002.02.xsd:sepade.pain.008.003.02.xsd", ""));
|
||||
bankParameters.add(new GlobalParameter("HISPAS", 2, 1, "1", "1", "J:N:N:N:sepade.pain.001.001.02.xsd:sepade.pain.001.002.02.xsd:sepade.pain.001.001.03.xsd:sepade.pain.001.002.03.xsd:sepade.pain.008.001.02.xsd:sepade.pain.008.002.02.xsd:sepade.pain.008.003.02.xsd", ""));
|
||||
//19 Überweisung IZV
|
||||
bankParameters.add(new GlobalParameter("HIUEBS", 5, 1, "1", "2", "14:51:53:54:67:69", ""));
|
||||
bankParameters.add(new GlobalParameter("HITANS", 6, 1, "1", "1", "J:N:1:" + mTAN.getElementVersion6String(), ""));
|
||||
bankParameters.add(new GlobalParameter("HIPAES", 1, 1, "1", "1", "", ""));//PIN ändern
|
||||
bankParameters.add(new GlobalParameter("HIKOMS", 4, 1, "1", "1", "", ""));//Kommunikationszugänge
|
||||
bankParameters.add(new GlobalParameter("HIKDMS", 5, 1, "1", "1", "2048", ""));
|
||||
bankParameters.add(new GlobalParameter("HIVMKS", 1, 1, "1", "1", "N:N", ""));
|
||||
bankParameters.add(new GlobalParameter("HICSES", 1, 1, "1", "2", "1:14", ""));
|
||||
bankParameters.add(new GlobalParameter("HICMES", 1, 10, "1", "2", "1:14:0:N:J", ""));
|
||||
bankParameters.add(new GlobalParameter("HICSBS", 1, 1, "1", "1", "N:N", ""));
|
||||
bankParameters.add(new GlobalParameter("HICMBS", 1, 1, "1", "1", "N:N", ""));
|
||||
bankParameters.add(new GlobalParameter("HICSLS", 1, 1, "1", "2", "N" ,""));
|
||||
bankParameters.add(new GlobalParameter("HICMLS", 1, 1, "1", "2", "", ""));
|
||||
bankParameters.add(new GlobalParameter("HIBBSS", 1, 1, "1", "1", "J:N", "")); //Bestand Firmeneinzellastschrift
|
||||
bankParameters.add(new GlobalParameter("HIBMES", 1, 1, "1", "1", "1:14:1:14:1000:N:J", "")); //Einreichung Firmensammellastschrift
|
||||
bankParameters.add(new GlobalParameter("HIBMLS", 1, 1, "1", "1", "", "")); //Firmensammellastschrift löschen
|
||||
bankParameters.add(new GlobalParameter("HIBSES", 1, 1, "1", "2", "1:14:1:14", "")); //Einreichung Firmeneinzellastschrift
|
||||
bankParameters.add(new GlobalParameter("HIBSLS", 1, 1, "1", "1", "J", "")); //Firmeneinzellastschrift löschen
|
||||
}
|
||||
return bankParameters;
|
||||
}
|
||||
|
||||
public static String getHBCIversion(FinTSVersionSwitch.FinTSVersion fintsVersion)
|
||||
{
|
||||
String hbciversion;
|
||||
switch (fintsVersion)
|
||||
{
|
||||
case HBCI_VERSION_2_2:
|
||||
hbciversion = "220";
|
||||
break;
|
||||
default:
|
||||
case FINTS_VERSION_3_0:
|
||||
hbciversion = "300";
|
||||
break;
|
||||
case FINTS_VERSION_4_0:
|
||||
hbciversion = "400";
|
||||
break;
|
||||
}
|
||||
return hbciversion;
|
||||
}
|
||||
|
||||
/**
|
||||
* HKXXX zu FINTS30 Geschäftsvorfall
|
||||
* @param type FINTS30
|
||||
* @return String "HKXXX"
|
||||
*/
|
||||
public static String getGeschaeftsvorfall(FINTS30 type)
|
||||
{
|
||||
if (geschaeftsvorfaelle.containsKey(type))
|
||||
{
|
||||
return geschaeftsvorfaelle.get(type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* FINTS30 Geschäftsvorfall zum String
|
||||
* @param value "HKXXX"
|
||||
* @return FINTS30 Geschäftsvorfall
|
||||
*/
|
||||
public static FINTS30 getGeschaeftsvorfall(String value)
|
||||
{
|
||||
for (Map.Entry<FINTS30, String> entry : geschaeftsvorfaelle.entrySet())
|
||||
{
|
||||
if (value.equals(entry.getValue()))
|
||||
{
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste "aller" FINTS30-Geschäftsvorfälle und ob für diese eine PIN-Eingabe benötigt wird
|
||||
* @return Liste mit true/false-Values
|
||||
*/
|
||||
public static HashMap<FINTS30, Boolean> getPinRequired()
|
||||
{
|
||||
if (pinRequired == null)
|
||||
{
|
||||
pinRequired = new HashMap<>();
|
||||
pinRequired.put(FINTS30.SaldoAbfrage, false);
|
||||
pinRequired.put(FINTS30.UmsatzAbfrage, false);
|
||||
pinRequired.put(FINTS30.PinTanVerfahren, false);
|
||||
pinRequired.put(FINTS30.PinAendern, true);
|
||||
pinRequired.put(FINTS30.SepaKontoVerbindungen, false);
|
||||
pinRequired.put(FINTS30.SepaUeberweisungEinzelEinreichen, true);
|
||||
pinRequired.put(FINTS30.SepaUeberweisungEinzelTerminEinreichen,true);
|
||||
pinRequired.put(FINTS30.SepaUeberweisungEinzelTerminBestand,false);
|
||||
pinRequired.put(FINTS30.SepaUeberweisungEinzelTerminLoeschen,true);
|
||||
pinRequired.put(FINTS30.SepaUeberweisungSammelEinreichen, true);
|
||||
pinRequired.put(FINTS30.SepaUeberweisungSammelTerminEinreichen,true);
|
||||
pinRequired.put(FINTS30.SepaUeberweisungSammelTerminBestand,false);
|
||||
pinRequired.put(FINTS30.SepaUeberweisungSammelTerminLoeschen,true);
|
||||
pinRequired.put(FINTS30.SepaLastschriftEinzelAendern, true);
|
||||
pinRequired.put(FINTS30.SepaLastschriftEinzelEinreichen, true);
|
||||
pinRequired.put(FINTS30.SepaLastschriftEinzelEinreichenCore1, true);
|
||||
pinRequired.put(FINTS30.SepaLastschriftEinzelLoeschen, true);
|
||||
pinRequired.put(FINTS30.SepaLastschriftEinzelBestand, false);
|
||||
pinRequired.put(FINTS30.SepaLastschriftSammelEinreichen, true);
|
||||
pinRequired.put(FINTS30.SepaLastschriftSammelEinreichenCore1,true);
|
||||
pinRequired.put(FINTS30.SepaLastschriftSammelLoeschen, true);
|
||||
pinRequired.put(FINTS30.SepaLastschriftSammelBestand, false);
|
||||
pinRequired.put(FINTS30.KundenBankNachricht,false);
|
||||
pinRequired.put(FINTS30.Vormerkumsaetze,false);
|
||||
pinRequired.put(FINTS30.Identifikation, true);
|
||||
}
|
||||
return pinRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert PIN-Parameter-Objekt für iTAN
|
||||
* @return Object
|
||||
*/
|
||||
private static TanProcessParameterObject getiTanParameter()
|
||||
{
|
||||
TanProcessParameterObject iTanParameter = new TanProcessParameterObject();
|
||||
iTanParameter.setNameDesZweiSchrittVerfahrens("iTAN-Liste");
|
||||
iTanParameter.setBelegungsText("Erhaltene TAN");
|
||||
iTanParameter.setSicherheitsfunktion_kodiert(verfahren_iTan);
|
||||
iTanParameter.setTechnischeIdentifikationTanVerfahren("iTAN");
|
||||
return iTanParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert PIN-Parameter-Objekt für mTAN
|
||||
* @return Object
|
||||
*/
|
||||
private static TanProcessParameterObject getmTanParameter()
|
||||
{
|
||||
TanProcessParameterObject mTanParameter = new TanProcessParameterObject();
|
||||
mTanParameter.setNameDesZweiSchrittVerfahrens("Mobile TAN");
|
||||
mTanParameter.setBelegungsText("Erhaltene TAN");
|
||||
mTanParameter.setSicherheitsfunktion_kodiert(verfahren_mTan);
|
||||
mTanParameter.setTechnischeIdentifikationTanVerfahren("mTAN");
|
||||
return mTanParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert PIN-Parameter-Objekt für iTAN per SMS
|
||||
* @return Object
|
||||
*/
|
||||
private static TanProcessParameterObject getiTanSmsParameter()
|
||||
{
|
||||
TanProcessParameterObject iTanSmsParameter = new TanProcessParameterObject();
|
||||
iTanSmsParameter.setNameDesZweiSchrittVerfahrens("iTAN-Liste-Mobil");
|
||||
iTanSmsParameter.setBelegungsText("Erhaltene TAN");
|
||||
iTanSmsParameter.setSicherheitsfunktion_kodiert(verfahren_iTanSms);
|
||||
iTanSmsParameter.setTechnischeIdentifikationTanVerfahren("iTANm");
|
||||
return iTanSmsParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Für die Generierung des Strings der Geschäftsvofälle pro konto
|
||||
* @param type FINTS30, es sollten nur erlaubte hier auftrauchen
|
||||
*/
|
||||
public void addPermission(FINTS30 type)
|
||||
{
|
||||
String gvf = getGeschaeftsvorfall(type);
|
||||
if (!permissions.equals(""))
|
||||
{
|
||||
permissions += "+";
|
||||
}
|
||||
permissions += gvf + ":1";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den Geschäftsvorfallstring zurück
|
||||
* @return String "HKXXX:1+HKXXX:1+..."
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liste aller Geschäftsvorfälle
|
||||
*/
|
||||
public enum FINTS30
|
||||
{
|
||||
SaldoAbfrage,
|
||||
UmsatzAbfrage,
|
||||
PinTanVerfahren,
|
||||
SepaKontoVerbindungen,
|
||||
SepaUeberweisungEinzelEinreichen,
|
||||
SepaUeberweisungEinzelTerminEinreichen,
|
||||
SepaUeberweisungEinzelTerminBestand,
|
||||
SepaUeberweisungEinzelTerminLoeschen,
|
||||
SepaUeberweisungSammelEinreichen,
|
||||
SepaUeberweisungSammelTerminEinreichen,
|
||||
SepaUeberweisungSammelTerminBestand,
|
||||
SepaUeberweisungSammelTerminLoeschen,
|
||||
SepaLastschriftEinzelEinreichen,
|
||||
SepaLastschriftEinzelLoeschen,
|
||||
SepaLastschriftEinzelAendern,
|
||||
SepaLastschriftEinzelEinreichenCore1,
|
||||
SepaLastschriftEinzelBestand,
|
||||
SepaLastschriftSammelEinreichenCore1,
|
||||
SepaLastschriftSammelEinreichen,
|
||||
SepaLastschriftSammelLoeschen,
|
||||
SepaLastschriftSammelBestand,
|
||||
PinTanZweiSchrittParameter,
|
||||
PinAendern,
|
||||
KundenBankNachricht,
|
||||
Vormerkumsaetze,
|
||||
SepaLastschriftEinzelLoeschenB2B,
|
||||
SepaLastschriftEinzelEinreichenB2B,
|
||||
SepaLastschriftEinzelBestandB2B,
|
||||
SepaLastschriftSammelEinreichenB2B,
|
||||
SepaLastschriftSammelBestandB2B,
|
||||
SepaLastschriftSammelLoeschenB2B,
|
||||
Identifikation
|
||||
}
|
||||
|
||||
/**
|
||||
* Generelle Bankparameter
|
||||
*/
|
||||
public static class GlobalParameter
|
||||
{
|
||||
private final String segmentName;
|
||||
private final Integer segmentVersion;
|
||||
private final Integer maximaleAnzahlAuftraege;
|
||||
private final String anzahlSingaturenMindestens;
|
||||
private final String sicherheitsKlasse;
|
||||
private final String fints_3_parameter;
|
||||
private final String fints_4_parameter;
|
||||
|
||||
GlobalParameter(String segmentName,
|
||||
Integer segmentVersion, Integer maximaleAnzahlAuftraege, String anzahlSignaturenMindestens,
|
||||
String sicherheitsKlasse, String fints_3_parameter, String fints_4_parameter)
|
||||
{
|
||||
this.segmentName = segmentName;
|
||||
this.segmentVersion = segmentVersion;
|
||||
this.maximaleAnzahlAuftraege = maximaleAnzahlAuftraege;
|
||||
this.anzahlSingaturenMindestens = anzahlSignaturenMindestens;
|
||||
this.sicherheitsKlasse = sicherheitsKlasse;
|
||||
this.fints_3_parameter = fints_3_parameter;
|
||||
this.fints_4_parameter = fints_4_parameter;
|
||||
|
||||
}
|
||||
|
||||
public String getFints_4_parameter()
|
||||
{
|
||||
return fints_4_parameter;
|
||||
}
|
||||
|
||||
public String getFints_3_parameter()
|
||||
{
|
||||
return fints_3_parameter;
|
||||
}
|
||||
|
||||
public String getSicherheitsKlasse()
|
||||
{
|
||||
return sicherheitsKlasse;
|
||||
}
|
||||
|
||||
public String getAnzahlSingaturenMindestens()
|
||||
{
|
||||
return anzahlSingaturenMindestens;
|
||||
}
|
||||
|
||||
public Integer getMaximaleAnzahlAuftraege()
|
||||
{
|
||||
return maximaleAnzahlAuftraege;
|
||||
}
|
||||
|
||||
public Integer getSegmentVersion()
|
||||
{
|
||||
return segmentVersion;
|
||||
}
|
||||
|
||||
public String getSegmentName()
|
||||
{
|
||||
return segmentName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.GeschaeftsvorfallspezifischePinTanInformation;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class PinParameterObject {
|
||||
private Integer maximaleAnzahlAuftraege;
|
||||
private Integer anzahlSignaturenMindestens;
|
||||
private Integer sicherheitsklasse = 0;
|
||||
private Integer minPinLaenge;
|
||||
private Integer maxPinLaenge;
|
||||
private Integer maxTanLaenge;
|
||||
private String textBelegungBenutzerkennung;
|
||||
private String textBelegungKundenId;
|
||||
private List<GeschaeftsvorfallspezifischePinTanInformation> tanInfo = new LinkedList<GeschaeftsvorfallspezifischePinTanInformation>();
|
||||
|
||||
public Integer getMaximaleAnzahlAuftraege() {
|
||||
return maximaleAnzahlAuftraege;
|
||||
}
|
||||
|
||||
public void setMaximaleAnzahlAuftraege(Integer maximaleAnzahlAuftraege) {
|
||||
this.maximaleAnzahlAuftraege = maximaleAnzahlAuftraege;
|
||||
}
|
||||
|
||||
public Integer getAnzahlSignaturenMindestens() {
|
||||
return anzahlSignaturenMindestens;
|
||||
}
|
||||
|
||||
public void setAnzahlSignaturenMindestens(Integer anzahlSignaturenMindestens) {
|
||||
this.anzahlSignaturenMindestens = anzahlSignaturenMindestens;
|
||||
}
|
||||
|
||||
public Integer getMinPinLaenge() {
|
||||
return minPinLaenge;
|
||||
}
|
||||
|
||||
public void setMinPinLaenge(Integer minPinLaenge) {
|
||||
this.minPinLaenge = minPinLaenge;
|
||||
}
|
||||
|
||||
public Integer getMaxPinLaenge() {
|
||||
return maxPinLaenge;
|
||||
}
|
||||
|
||||
public void setMaxPinLaenge(Integer maxPinLaenge) {
|
||||
this.maxPinLaenge = maxPinLaenge;
|
||||
}
|
||||
|
||||
public Integer getMaxTanLaenge() {
|
||||
return maxTanLaenge;
|
||||
}
|
||||
|
||||
public void setMaxTanLaenge(Integer maxTanLaenge) {
|
||||
this.maxTanLaenge = maxTanLaenge;
|
||||
}
|
||||
|
||||
public String getTextBelegungBenutzerkennung() {
|
||||
return textBelegungBenutzerkennung;
|
||||
}
|
||||
|
||||
public void setTextBelegungBenutzerkennung(String textBelegungBenutzerkennung) {
|
||||
this.textBelegungBenutzerkennung = textBelegungBenutzerkennung;
|
||||
}
|
||||
|
||||
public String getTextBelegungKundenId() {
|
||||
return textBelegungKundenId;
|
||||
}
|
||||
|
||||
public void setTextBelegungKundenId(String textBelegungKundenId) {
|
||||
this.textBelegungKundenId = textBelegungKundenId;
|
||||
}
|
||||
|
||||
public void addSegment(String segmentkennung, boolean tanErforderlich) {
|
||||
GeschaeftsvorfallspezifischePinTanInformation geschaeftsvorfallspezifischePinTanInformation = new GeschaeftsvorfallspezifischePinTanInformation(segmentkennung, tanErforderlich);
|
||||
tanInfo.add(geschaeftsvorfallspezifischePinTanInformation);
|
||||
}
|
||||
|
||||
public List<GeschaeftsvorfallspezifischePinTanInformation> getGeschaeftsvorfallspezifischePinTanInformationen() {
|
||||
return tanInfo;
|
||||
}
|
||||
|
||||
public Integer getSicherheitsklasse() {
|
||||
return sicherheitsklasse;
|
||||
}
|
||||
|
||||
public void setSicherheitsklasse(Integer sicherheitsklasse) {
|
||||
this.sicherheitsklasse = sicherheitsklasse;
|
||||
}
|
||||
|
||||
public boolean isTanErforderlich(String segmentkennung) {
|
||||
for (GeschaeftsvorfallspezifischePinTanInformation info: tanInfo) {
|
||||
if (info.getSegmentkennung().equals(segmentkennung))
|
||||
return info.getTanErforderlich().equals("J");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
/**
|
||||
* Enhält Daten für Empfängerkonten. (SEPA-Übertrag)
|
||||
*/
|
||||
public class RecipientAccountDataObject {
|
||||
private String IBAN;
|
||||
private String BIC;
|
||||
private String name;
|
||||
|
||||
public String getIBAN() {
|
||||
return IBAN;
|
||||
}
|
||||
|
||||
public void setIBAN(String IBAN) {
|
||||
this.IBAN = IBAN;
|
||||
}
|
||||
|
||||
public String getBIC() {
|
||||
return BIC;
|
||||
}
|
||||
|
||||
public void setBIC(String BIC) {
|
||||
this.BIC = BIC;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
public class ReturnDataObject {
|
||||
private boolean success = false;
|
||||
private String message;
|
||||
private String returnCode;
|
||||
private Object additionalData = null;
|
||||
|
||||
public ReturnDataObject(boolean success, String message) {
|
||||
this(success, message, null);
|
||||
}
|
||||
|
||||
public ReturnDataObject(boolean success, String message, String code) {
|
||||
this.success = success;
|
||||
this.message = message;
|
||||
this.returnCode = code;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getReturnCode() {
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
public void setReturnCode(String returnCode) {
|
||||
this.returnCode = returnCode;
|
||||
}
|
||||
|
||||
public Object getAdditionalData() {
|
||||
return additionalData;
|
||||
}
|
||||
|
||||
public ReturnDataObject setAdditionalData(Object additionalData) {
|
||||
this.additionalData = additionalData;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
public class SaldoDataObject {
|
||||
private double gebuchterSaldo = 0d;
|
||||
private Double vorgemerkterSaldo = null;
|
||||
private Double verfuegbarerBetrag = null;
|
||||
private Double kreditlinie = null; // verfügbarer Betrag - gebuchterSaldo
|
||||
private String waehrung = "EUR"; // EUR ist standard für deutsche Konten
|
||||
private Double verfuegbarTag=null;
|
||||
private boolean isOverdrawAllowed = false;
|
||||
|
||||
public double getGebuchterSaldo() {
|
||||
return gebuchterSaldo;
|
||||
}
|
||||
|
||||
public void setGebuchterSaldo(double gebuchterSaldo) {
|
||||
this.gebuchterSaldo = gebuchterSaldo;
|
||||
}
|
||||
|
||||
public Double getVorgemerkterSaldo() {
|
||||
return vorgemerkterSaldo;
|
||||
}
|
||||
|
||||
public void setVorgemerkterSaldo(Double vorgemerkterSaldo) {
|
||||
this.vorgemerkterSaldo = vorgemerkterSaldo;
|
||||
}
|
||||
|
||||
public Double getVerfuegbarerBetrag() {
|
||||
return verfuegbarerBetrag;
|
||||
}
|
||||
|
||||
public void setVerfuegbarerBetrag(Double verfuegbarerBetrag) {
|
||||
this.verfuegbarerBetrag = verfuegbarerBetrag;
|
||||
}
|
||||
|
||||
public Double getKreditlinie() {
|
||||
return kreditlinie;
|
||||
}
|
||||
|
||||
public void setKreditlinie(Double kreditlinie) {
|
||||
this.kreditlinie = kreditlinie;
|
||||
}
|
||||
|
||||
public String getWaehrung() {
|
||||
return waehrung;
|
||||
}
|
||||
|
||||
public void setWaehrung(String waehrung) {
|
||||
this.waehrung = waehrung;
|
||||
}
|
||||
public void setVerfuegbarTag(Double verfuegbarTag)
|
||||
{
|
||||
this.verfuegbarTag = verfuegbarTag;
|
||||
}
|
||||
|
||||
public Double getVerfuegbarTag()
|
||||
{
|
||||
return verfuegbarTag;
|
||||
}
|
||||
|
||||
public boolean isOverdrawAllowed() {
|
||||
return isOverdrawAllowed;
|
||||
}
|
||||
|
||||
public void setOverdrawAllowed(boolean overdrawAllowed) {
|
||||
isOverdrawAllowed = overdrawAllowed;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,417 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects;
|
||||
|
||||
/**
|
||||
* Enthält Informationen zu einem TanProzess, die unter anderem in HITANS (FinTS 3.0) benutzt werden
|
||||
* <p/>
|
||||
* Damit der TanProzess funktionieren kann, müssen folgende Parameter gesetzt werden:
|
||||
* <p/>
|
||||
* * sicherheitsfunktion_kodiert
|
||||
* * technischeIdentifikationTanVerfahren
|
||||
* * nameDesZweiSchrittVerfahrens
|
||||
* * belegungstext
|
||||
*/
|
||||
public class TanProcessParameterObject implements IDataObject {
|
||||
|
||||
|
||||
private String sicherheitsfunktion_kodiert = "";
|
||||
|
||||
private String tanProzess = "1";
|
||||
|
||||
private String technischeIdentifikationTanVerfahren = "";
|
||||
|
||||
private String zkaTanVerfahren = "";
|
||||
|
||||
private String versionZkaTanVerfahren = "";
|
||||
|
||||
private String nameDesZweiSchrittVerfahrens = "";
|
||||
|
||||
private String maximaleLaengeDesEingabewertes = "10";
|
||||
|
||||
/*
|
||||
* 1: numerisch
|
||||
* 2: alphanumerisch
|
||||
*/
|
||||
private String erlaubtesFormat = "2";
|
||||
|
||||
private String belegungsText = "";
|
||||
|
||||
private String maximaleLaengeDesRueckgabewertes = "256";
|
||||
|
||||
private String anzahlUnterstuetzerTanListen = "1";
|
||||
|
||||
private String mehrfachTanErlaubt = "N";
|
||||
|
||||
/*
|
||||
* 1: TAN nicht zeitversetzt / dialogübergreifend erlaubt;
|
||||
* 2: TAN zeitversetzt / dialogübergreifend erlaubt;
|
||||
* 3: beide Verfahren unterstützt;
|
||||
* 4: nicht zutreffend
|
||||
*
|
||||
* Bei Prozessvariante 1 ist der Parameter immer mit „nicht zutreffend“ zu belegen, da hier generell keine zeitversetzte Verarbeitung möglich ist.
|
||||
*/
|
||||
private String tanZeitUndDialogBezug = "4";
|
||||
|
||||
/*
|
||||
* 0: TAN-Listennummer darf nicht angegeben werden
|
||||
* 1: TAN-Listennummer kann angegeben werden
|
||||
* 2: TAN-Listennummer muss angegeben werden
|
||||
*/
|
||||
private String tanListenNummerErforderlich = "0";
|
||||
|
||||
private String auftragsStornoErlaubt = "N";
|
||||
|
||||
private String smsAbbuchungsKontoErforderlich = "0";
|
||||
|
||||
private String auftraggeberKontoErforderlich = "0";
|
||||
|
||||
private String challengeKlasseErforderlich = "N";
|
||||
|
||||
private String challengeBetragErforderlich = "N";
|
||||
|
||||
/*
|
||||
* Über diesen BPD-Parameter erhält die Kundenseite die Information,
|
||||
* dass im Datenelement „Challenge“ Formatsteuerzeichen enthalten sein können.
|
||||
*/
|
||||
private String challengeStrukturiert = "N";
|
||||
|
||||
/*
|
||||
* 00: Initialisierungsverfahren mit Klartext-PIN ohne TAN
|
||||
* 01: Verwendung analog der in [HHD] beschriebenen Schablone 01 – ver- schlüsselte PIN und ohne TAN
|
||||
* 02: Verwendung analog der in [HHD] beschriebenen Schablone 02 – reser- viert, bei FinTS derzeit nicht verwendet
|
||||
*/
|
||||
private String initialisierungsModus = "00";
|
||||
|
||||
/*
|
||||
* 0: Bezeichnung des TAN-Mediums darf nicht angegeben werden
|
||||
* 1: Bezeichnung des TAN-Mediums kann angegeben werden
|
||||
* 2: Bezeichnung des TAN-Mediums muss angegeben werden
|
||||
*/
|
||||
private String bezeichnungDesTanMediumsErforderlich = "0";
|
||||
|
||||
private String anzahlUnterstuetzterTanMedien = "1";
|
||||
|
||||
public String getElementVersion1String() {
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
sb.append(sicherheitsfunktion_kodiert + ":");
|
||||
sb.append(tanProzess + ":");
|
||||
sb.append(technischeIdentifikationTanVerfahren + ":");
|
||||
sb.append(nameDesZweiSchrittVerfahrens + ":");
|
||||
sb.append(maximaleLaengeDesEingabewertes + ":");
|
||||
sb.append(erlaubtesFormat + ":");
|
||||
sb.append(belegungsText + ":");
|
||||
sb.append(maximaleLaengeDesRueckgabewertes + ":");
|
||||
sb.append(anzahlUnterstuetzerTanListen + ":");
|
||||
sb.append(mehrfachTanErlaubt + ":");
|
||||
sb.append(tanZeitUndDialogBezug.equals("4") ? "N" : "J");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getElementVersion2String() {
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
sb.append(sicherheitsfunktion_kodiert + ":");
|
||||
sb.append(tanProzess + ":");
|
||||
sb.append(technischeIdentifikationTanVerfahren + ":");
|
||||
sb.append(nameDesZweiSchrittVerfahrens + ":");
|
||||
sb.append(maximaleLaengeDesEingabewertes + ":");
|
||||
sb.append(erlaubtesFormat + ":");
|
||||
sb.append(belegungsText + ":");
|
||||
sb.append(maximaleLaengeDesRueckgabewertes + ":");
|
||||
sb.append(anzahlUnterstuetzerTanListen + ":");
|
||||
sb.append(mehrfachTanErlaubt + ":");
|
||||
sb.append(tanZeitUndDialogBezug + ":");
|
||||
sb.append(tanListenNummerErforderlich + ":");
|
||||
sb.append(auftragsStornoErlaubt + ":");
|
||||
sb.append(challengeKlasseErforderlich + ":");
|
||||
sb.append(challengeBetragErforderlich);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getElementVersion3String() {
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
sb.append(sicherheitsfunktion_kodiert + ":");
|
||||
sb.append(tanProzess + ":");
|
||||
sb.append(technischeIdentifikationTanVerfahren + ":");
|
||||
sb.append(nameDesZweiSchrittVerfahrens + ":");
|
||||
sb.append(maximaleLaengeDesEingabewertes + ":");
|
||||
sb.append(erlaubtesFormat + ":");
|
||||
sb.append(belegungsText + ":");
|
||||
sb.append(maximaleLaengeDesRueckgabewertes + ":");
|
||||
sb.append(anzahlUnterstuetzerTanListen + ":");
|
||||
sb.append(mehrfachTanErlaubt + ":");
|
||||
sb.append(tanZeitUndDialogBezug + ":");
|
||||
sb.append(tanListenNummerErforderlich + ":");
|
||||
sb.append(auftragsStornoErlaubt + ":");
|
||||
sb.append(challengeKlasseErforderlich + ":");
|
||||
sb.append(challengeBetragErforderlich + ":");
|
||||
sb.append(initialisierungsModus + ":");
|
||||
sb.append(bezeichnungDesTanMediumsErforderlich + ":");
|
||||
sb.append(anzahlUnterstuetzterTanMedien);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getElementVersion4String() {
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
sb.append(sicherheitsfunktion_kodiert + ":");
|
||||
sb.append(tanProzess + ":");
|
||||
sb.append(technischeIdentifikationTanVerfahren + ":");
|
||||
sb.append(zkaTanVerfahren + ":");
|
||||
sb.append(versionZkaTanVerfahren + ":");
|
||||
sb.append(nameDesZweiSchrittVerfahrens + ":");
|
||||
sb.append(maximaleLaengeDesEingabewertes + ":");
|
||||
sb.append(erlaubtesFormat + ":");
|
||||
sb.append(belegungsText + ":");
|
||||
sb.append(maximaleLaengeDesRueckgabewertes + ":");
|
||||
sb.append(anzahlUnterstuetzerTanListen + ":");
|
||||
sb.append(mehrfachTanErlaubt + ":");
|
||||
sb.append(tanZeitUndDialogBezug + ":");
|
||||
sb.append(tanListenNummerErforderlich + ":");
|
||||
sb.append(auftragsStornoErlaubt + ":");
|
||||
sb.append((smsAbbuchungsKontoErforderlich.equals("0") ? "N" : "J") + ":");
|
||||
sb.append(challengeKlasseErforderlich + ":");
|
||||
sb.append(challengeBetragErforderlich + ":");
|
||||
sb.append(challengeStrukturiert + ":");
|
||||
sb.append(initialisierungsModus + ":");
|
||||
sb.append(bezeichnungDesTanMediumsErforderlich + ":");
|
||||
sb.append(anzahlUnterstuetzterTanMedien);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getElementVersion5String() {
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
sb.append(sicherheitsfunktion_kodiert + ":");
|
||||
sb.append(tanProzess + ":");
|
||||
sb.append(technischeIdentifikationTanVerfahren + ":");
|
||||
sb.append(zkaTanVerfahren + ":");
|
||||
sb.append(versionZkaTanVerfahren + ":");
|
||||
sb.append(nameDesZweiSchrittVerfahrens + ":");
|
||||
sb.append(maximaleLaengeDesEingabewertes + ":");
|
||||
sb.append(erlaubtesFormat + ":");
|
||||
sb.append(belegungsText + ":");
|
||||
sb.append(maximaleLaengeDesRueckgabewertes + ":");
|
||||
sb.append(anzahlUnterstuetzerTanListen + ":");
|
||||
sb.append(mehrfachTanErlaubt + ":");
|
||||
sb.append(tanZeitUndDialogBezug + ":");
|
||||
sb.append(tanListenNummerErforderlich + ":");
|
||||
sb.append(auftragsStornoErlaubt + ":");
|
||||
sb.append(smsAbbuchungsKontoErforderlich + ":");
|
||||
sb.append(auftraggeberKontoErforderlich + ":");
|
||||
sb.append(challengeKlasseErforderlich + ":");
|
||||
sb.append(challengeStrukturiert + ":");
|
||||
sb.append(initialisierungsModus + ":");
|
||||
sb.append(bezeichnungDesTanMediumsErforderlich + ":");
|
||||
sb.append(anzahlUnterstuetzterTanMedien);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getElementVersion6String() {
|
||||
StringBuilder sb = new StringBuilder("");
|
||||
sb.append(sicherheitsfunktion_kodiert + ":");
|
||||
sb.append(tanProzess + ":");
|
||||
sb.append(technischeIdentifikationTanVerfahren + ":");
|
||||
sb.append(zkaTanVerfahren + ":");
|
||||
sb.append(versionZkaTanVerfahren + ":");
|
||||
sb.append(nameDesZweiSchrittVerfahrens + ":");
|
||||
sb.append(maximaleLaengeDesEingabewertes + ":");
|
||||
sb.append(erlaubtesFormat + ":");
|
||||
sb.append(belegungsText + ":");
|
||||
sb.append(maximaleLaengeDesRueckgabewertes + ":");
|
||||
sb.append(mehrfachTanErlaubt + ":");
|
||||
sb.append(tanZeitUndDialogBezug + ":");
|
||||
sb.append(auftragsStornoErlaubt + ":");
|
||||
sb.append(smsAbbuchungsKontoErforderlich + ":");
|
||||
sb.append(auftraggeberKontoErforderlich + ":");
|
||||
sb.append(challengeKlasseErforderlich + ":");
|
||||
sb.append(challengeStrukturiert + ":");
|
||||
sb.append(initialisierungsModus + ":");
|
||||
sb.append(bezeichnungDesTanMediumsErforderlich + ":");
|
||||
sb.append("N:");
|
||||
sb.append(anzahlUnterstuetzterTanMedien);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getSicherheitsfunktion_kodiert() {
|
||||
return sicherheitsfunktion_kodiert;
|
||||
}
|
||||
|
||||
public void setSicherheitsfunktion_kodiert(String sicherheitsfunktion_kodiert) {
|
||||
this.sicherheitsfunktion_kodiert = sicherheitsfunktion_kodiert;
|
||||
}
|
||||
|
||||
public String getTanProzess() {
|
||||
return tanProzess;
|
||||
}
|
||||
|
||||
public void setTanProzess(String tanProzess) {
|
||||
this.tanProzess = tanProzess;
|
||||
}
|
||||
|
||||
public String getTechnischeIdentifikationTanVerfahren() {
|
||||
return technischeIdentifikationTanVerfahren;
|
||||
}
|
||||
|
||||
public void setTechnischeIdentifikationTanVerfahren(String technischeIdentifikationTanVerfahren) {
|
||||
this.technischeIdentifikationTanVerfahren = technischeIdentifikationTanVerfahren;
|
||||
}
|
||||
|
||||
public String getZkaTanVerfahren() {
|
||||
return zkaTanVerfahren;
|
||||
}
|
||||
|
||||
public void setZkaTanVerfahren(String zkaTanVerfahren) {
|
||||
this.zkaTanVerfahren = zkaTanVerfahren;
|
||||
}
|
||||
|
||||
public String getVersionZkaTanVerfahren() {
|
||||
return versionZkaTanVerfahren;
|
||||
}
|
||||
|
||||
public void setVersionZkaTanVerfahren(String versionZkaTanVerfahren) {
|
||||
this.versionZkaTanVerfahren = versionZkaTanVerfahren;
|
||||
}
|
||||
|
||||
public String getNameDesZweiSchrittVerfahrens() {
|
||||
return nameDesZweiSchrittVerfahrens;
|
||||
}
|
||||
|
||||
public void setNameDesZweiSchrittVerfahrens(String nameDesZweiSchrittVerfahrens) {
|
||||
this.nameDesZweiSchrittVerfahrens = nameDesZweiSchrittVerfahrens;
|
||||
}
|
||||
|
||||
public String getMaximaleLaengeDesEingabewertes() {
|
||||
return maximaleLaengeDesEingabewertes;
|
||||
}
|
||||
|
||||
public void setMaximaleLaengeDesEingabewertes(String maximaleLaengeDesEingabewertes) {
|
||||
this.maximaleLaengeDesEingabewertes = maximaleLaengeDesEingabewertes;
|
||||
}
|
||||
|
||||
public String getErlaubtesFormat() {
|
||||
return erlaubtesFormat;
|
||||
}
|
||||
|
||||
public void setErlaubtesFormat(String erlaubtesFormat) {
|
||||
this.erlaubtesFormat = erlaubtesFormat;
|
||||
}
|
||||
|
||||
public String getBelegungsText() {
|
||||
return belegungsText;
|
||||
}
|
||||
|
||||
public void setBelegungsText(String belegungsText) {
|
||||
this.belegungsText = belegungsText;
|
||||
}
|
||||
|
||||
public String getMaximaleLaengeDesRueckgabewertes() {
|
||||
return maximaleLaengeDesRueckgabewertes;
|
||||
}
|
||||
|
||||
public void setMaximaleLaengeDesRueckgabewertes(String maximaleLaengeDesRueckgabewertes) {
|
||||
this.maximaleLaengeDesRueckgabewertes = maximaleLaengeDesRueckgabewertes;
|
||||
}
|
||||
|
||||
public String getAnzahlUnterstuetzerTanListen() {
|
||||
return anzahlUnterstuetzerTanListen;
|
||||
}
|
||||
|
||||
public void setAnzahlUnterstuetzerTanListen(String anzahlUnterstuetzerTanListen) {
|
||||
this.anzahlUnterstuetzerTanListen = anzahlUnterstuetzerTanListen;
|
||||
}
|
||||
|
||||
public String getMehrfachTanErlaubt() {
|
||||
return mehrfachTanErlaubt;
|
||||
}
|
||||
|
||||
public void setMehrfachTanErlaubt(String mehrfachTanErlaubt) {
|
||||
this.mehrfachTanErlaubt = mehrfachTanErlaubt;
|
||||
}
|
||||
|
||||
public String getTanZeitUndDialogBezug() {
|
||||
return tanZeitUndDialogBezug;
|
||||
}
|
||||
|
||||
public void setTanZeitUndDialogBezug(String tanZeitUndDialogBezug) {
|
||||
this.tanZeitUndDialogBezug = tanZeitUndDialogBezug;
|
||||
}
|
||||
|
||||
public String getTanListenNummerErforderlich() {
|
||||
return tanListenNummerErforderlich;
|
||||
}
|
||||
|
||||
public void setTanListenNummerErforderlich(String tanListenNummerErforderlich) {
|
||||
this.tanListenNummerErforderlich = tanListenNummerErforderlich;
|
||||
}
|
||||
|
||||
public String getAuftragsStornoErlaubt() {
|
||||
return auftragsStornoErlaubt;
|
||||
}
|
||||
|
||||
public void setAuftragsStornoErlaubt(String auftragsStornoErlaubt) {
|
||||
this.auftragsStornoErlaubt = auftragsStornoErlaubt;
|
||||
}
|
||||
|
||||
public String getSmsAbbuchungsKontoErforderlich() {
|
||||
return smsAbbuchungsKontoErforderlich;
|
||||
}
|
||||
|
||||
public void setSmsAbbuchungsKontoErforderlich(String smsAbbuchungsKontoErforderlich) {
|
||||
this.smsAbbuchungsKontoErforderlich = smsAbbuchungsKontoErforderlich;
|
||||
}
|
||||
|
||||
public String getAuftraggeberKontoErforderlich() {
|
||||
return auftraggeberKontoErforderlich;
|
||||
}
|
||||
|
||||
public void setAuftraggeberKontoErforderlich(String auftraggeberKontoErforderlich) {
|
||||
this.auftraggeberKontoErforderlich = auftraggeberKontoErforderlich;
|
||||
}
|
||||
|
||||
public String getChallengeKlasseErforderlich() {
|
||||
return challengeKlasseErforderlich;
|
||||
}
|
||||
|
||||
public void setChallengeKlasseErforderlich(String challengeKlasseErforderlich) {
|
||||
this.challengeKlasseErforderlich = challengeKlasseErforderlich;
|
||||
}
|
||||
|
||||
public String getChallengeBetragErforderlich() {
|
||||
return challengeBetragErforderlich;
|
||||
}
|
||||
|
||||
public void setChallengeBetragErforderlich(String challengeBetragErforderlich) {
|
||||
this.challengeBetragErforderlich = challengeBetragErforderlich;
|
||||
}
|
||||
|
||||
public String getChallengeStrukturiert() {
|
||||
return challengeStrukturiert;
|
||||
}
|
||||
|
||||
public void setChallengeStrukturiert(String challengeStrukturiert) {
|
||||
this.challengeStrukturiert = challengeStrukturiert;
|
||||
}
|
||||
|
||||
public String getInitialisierungsModus() {
|
||||
return initialisierungsModus;
|
||||
}
|
||||
|
||||
public void setInitialisierungsModus(String initialisierungsModus) {
|
||||
this.initialisierungsModus = initialisierungsModus;
|
||||
}
|
||||
|
||||
public String getBezeichnungDesTanMediumsErforderlich() {
|
||||
return bezeichnungDesTanMediumsErforderlich;
|
||||
}
|
||||
|
||||
public void setBezeichnungDesTanMediumsErforderlich(String bezeichnungDesTanMediumsErforderlich) {
|
||||
this.bezeichnungDesTanMediumsErforderlich = bezeichnungDesTanMediumsErforderlich;
|
||||
}
|
||||
|
||||
public String getAnzahlUnterstuetzterTanMedien() {
|
||||
return anzahlUnterstuetzterTanMedien;
|
||||
}
|
||||
|
||||
public void setAnzahlUnterstuetzterTanMedien(String anzahlUnterstuetzterTanMedien) {
|
||||
this.anzahlUnterstuetzterTanMedien = anzahlUnterstuetzterTanMedien;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,42 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects.gateway;
|
||||
|
||||
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class email
|
||||
{
|
||||
|
||||
private final Session session;
|
||||
|
||||
public email(String smtphost, final String username, final String password)
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.auth", "true");
|
||||
props.put("mail.smtp.host", smtphost);
|
||||
session = Session.getInstance(props,
|
||||
new javax.mail.Authenticator()
|
||||
{
|
||||
protected PasswordAuthentication getPasswordAuthentication()
|
||||
{
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void sendMail(String absender, String empfaenger, String subject, String text) throws MessagingException
|
||||
{
|
||||
Message message = new MimeMessage(session);
|
||||
message.setFrom(new InternetAddress(absender));
|
||||
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(empfaenger));
|
||||
message.setSubject(subject);
|
||||
message.setText(text);
|
||||
Transport.send(message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
package net.petafuel.fuelifints.dataaccess.dataobjects.gateway;
|
||||
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNumeric;
|
||||
import static org.apache.commons.lang3.StringUtils.left;
|
||||
|
||||
public class sms
|
||||
{
|
||||
public static enum status
|
||||
{
|
||||
fail,
|
||||
okay,
|
||||
queued
|
||||
}
|
||||
private Charset charsetUTF8 = Charset.forName("UTF-8");
|
||||
private String configGatewayUrl = "http://yoursmsgateway.url/yousmsgateway.php";
|
||||
private String configSystemId = "";
|
||||
private String configSubSystemId = null;
|
||||
private String configGatewayId = null;
|
||||
private String configNotBefore = null;
|
||||
|
||||
public sms(String configSystemId, String configGatewayUrl)
|
||||
{
|
||||
this.configSystemId = configSystemId;
|
||||
this.configGatewayUrl = configGatewayUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sendete eine SMS ab
|
||||
* @param handyNummer Handynummer
|
||||
* @param message Nachricht
|
||||
* @param absender Absender (max 11 Zeichen Text oder Handynummer)
|
||||
* @return gibt zurück, ob die SMS erfolgreich versendet wurde
|
||||
* @throws Exception
|
||||
*/
|
||||
public status doSendSMS(String handyNummer, String message, String absender) throws Exception
|
||||
{
|
||||
if (absender != null && absender.isEmpty()) absender = null;
|
||||
if (configSystemId.isEmpty())
|
||||
{
|
||||
throw new Exception("Keine System-ID übergeben");
|
||||
}
|
||||
return doSendNew(handyNummer, message, absender);
|
||||
}
|
||||
|
||||
/**
|
||||
* SMS-Funktion zum versenden Über das SMS-Gateway
|
||||
*
|
||||
* @param handynummer Handynummer
|
||||
* @param message Nachricht
|
||||
* @param absender Absender
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
private status doSendNew(String handynummer, String message, String absender) throws Exception
|
||||
{
|
||||
|
||||
|
||||
if (absender != null)
|
||||
{
|
||||
absender = isNumeric(absender) ? formatHandynummer(absender, false) : left(absender,11);
|
||||
}
|
||||
URL url = new URL(configGatewayUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
|
||||
connection.setRequestProperty("systemid", configSystemId);
|
||||
connection.setRequestProperty("target", formatHandynummer(handynummer, true));
|
||||
connection.setRequestProperty("text", new String(Base64.encode(message.getBytes(charsetUTF8))));
|
||||
if (absender != null)
|
||||
{
|
||||
connection.setRequestProperty("sender", new String(Base64.encode(absender.getBytes(charsetUTF8))));
|
||||
}
|
||||
if (configSubSystemId != null)
|
||||
{
|
||||
connection.setRequestProperty("subsystemCustomer", configSubSystemId);
|
||||
}
|
||||
if (configGatewayId != null)
|
||||
{
|
||||
connection.setRequestProperty("gateway", configGatewayId);
|
||||
}
|
||||
if (configNotBefore != null)
|
||||
{
|
||||
connection.setRequestProperty("notbefore", configNotBefore);
|
||||
}
|
||||
connection.setUseCaches(false);
|
||||
connection.connect();
|
||||
if (connection.getResponseCode() == 200)
|
||||
{
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while ((line = rd.readLine()) != null)
|
||||
{
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
if(sb.toString().contains("OK"))
|
||||
{
|
||||
return status.okay;
|
||||
}
|
||||
else if(sb.toString().contains("QUEUED"))
|
||||
{
|
||||
return status.queued;
|
||||
}
|
||||
}
|
||||
return status.fail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert die Handynummer richtig
|
||||
*
|
||||
* @param handynummer Handynummer
|
||||
* @param international soll die Nummer am ende International sein?
|
||||
* @return Handynummer, formatiert
|
||||
*/
|
||||
private String formatHandynummer(String handynummer, boolean international)
|
||||
{
|
||||
handynummer = handynummer.replace("+", "00");
|
||||
if (!handynummer.startsWith("00"))
|
||||
{
|
||||
handynummer = "0049" + handynummer.substring(1);
|
||||
}
|
||||
if (!international)
|
||||
{
|
||||
handynummer = handynummer.replace("0049", "0");
|
||||
}
|
||||
return handynummer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzen der SubsystemID (für Abrechnung innerhalb eines Systems)
|
||||
*
|
||||
* @param configSubSystemId Subsystem-ID oder auch CustomerId
|
||||
*/
|
||||
public void setConfigSubSystemId(String configSubSystemId)
|
||||
{
|
||||
this.configSubSystemId = configSubSystemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bevorzugte Gateway-ID (eigentlich nur zum Testen)
|
||||
*
|
||||
* @param configGatewayId Gateway-ID
|
||||
*/
|
||||
public void setConfigGatewayId(String configGatewayId)
|
||||
{
|
||||
this.configGatewayId = configGatewayId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nicht senden vor ...
|
||||
*
|
||||
* @param configNotBefore MindestDatum
|
||||
*/
|
||||
public void setConfigNotBefore(String configNotBefore)
|
||||
{
|
||||
this.configNotBefore = configNotBefore;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package net.petafuel.fuelifints.exceptions;
|
||||
|
||||
public class DependencyResolveException extends Exception {
|
||||
|
||||
private String errorCode = "9000";
|
||||
|
||||
public DependencyResolveException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DependencyResolveException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DependencyResolveException(String message, String errorCode) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public void setErrorCode(String errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package net.petafuel.fuelifints.exceptions;
|
||||
|
||||
public class DeprecatedVersionHKTAN extends Exception {
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package net.petafuel.fuelifints.exceptions;
|
||||
|
||||
/**
|
||||
* Exception für Probleme, die beim Parsen einer Nachricht auftreten können
|
||||
*/
|
||||
|
||||
public class ElementParseException extends Exception {
|
||||
|
||||
public ElementParseException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
public ElementParseException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package net.petafuel.fuelifints.exceptions;
|
||||
|
||||
public class HBCISyntaxException extends Exception {
|
||||
public HBCISyntaxException(Exception ex) {
|
||||
super(ex);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package net.petafuel.fuelifints.exceptions;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMS;
|
||||
|
||||
public class HBCIValidationException extends Exception {
|
||||
|
||||
private HIRMS rueckmeldung;
|
||||
private boolean showDetails = true;
|
||||
|
||||
public HBCIValidationException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
|
||||
public HBCIValidationException(String reason, boolean showDetails) {
|
||||
super(reason);
|
||||
this.showDetails = showDetails;
|
||||
}
|
||||
|
||||
public HIRMS getRueckmeldung() {
|
||||
return rueckmeldung;
|
||||
}
|
||||
|
||||
public void setRueckmeldung(HIRMS rueckmeldung) {
|
||||
this.rueckmeldung = rueckmeldung;
|
||||
}
|
||||
|
||||
public boolean isShowDetails() {
|
||||
return showDetails;
|
||||
}
|
||||
|
||||
public void setShowDetails(boolean showDetails) {
|
||||
this.showDetails = showDetails;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package net.petafuel.fuelifints.exceptions;
|
||||
|
||||
public class UnregisteredClientProduct extends Exception {
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package net.petafuel.fuelifints.management;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.management.AttributeChangeNotification;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
public class CommunicationManagement extends NotificationBroadcasterSupport implements CommunicationManagementMBean {
|
||||
private static final Logger LOG = LogManager.getLogger(CommunicationManagement.class);
|
||||
public static final String DIALOG_TIMEOUT_MILLIS = "dialog.timeout.millis";
|
||||
private boolean nioMode = false;
|
||||
private int socketPort = 3000;
|
||||
private int sslPort = 443;
|
||||
private String server_ip = "";
|
||||
|
||||
private long sequenceNumber = 1;
|
||||
|
||||
public CommunicationManagement() {
|
||||
//Versuche, default Einstellungen aus einer property-Datei zu laden:
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("config/fuelifints.properties"));
|
||||
properties.load(bis);
|
||||
bis.close();
|
||||
System.getProperties().setProperty("hbci.security.protocols", properties.getProperty("hbci.security.protocols"));
|
||||
System.getProperties().setProperty(DIALOG_TIMEOUT_MILLIS, properties.getProperty(DIALOG_TIMEOUT_MILLIS));
|
||||
socketPort = Integer.parseInt(properties.getProperty("rdh_port"));
|
||||
sslPort = Integer.parseInt(properties.getProperty("ssl_port"));
|
||||
server_ip = properties.getProperty("server_ip");
|
||||
} catch (FileNotFoundException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNioMode() {
|
||||
return nioMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNioMode(boolean nioMode) {
|
||||
boolean oldmode = this.nioMode;
|
||||
this.nioMode = nioMode;
|
||||
|
||||
Notification n = new AttributeChangeNotification(this, sequenceNumber++,
|
||||
System.currentTimeMillis(), "Niomode changed", "nioMode", "boolean",
|
||||
oldmode, this.nioMode);
|
||||
sendNotification(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
String[] types = new String[]{
|
||||
AttributeChangeNotification.ATTRIBUTE_CHANGE
|
||||
};
|
||||
|
||||
String name = AttributeChangeNotification.class.getName();
|
||||
String description = "An attribute of this MBean has changed";
|
||||
MBeanNotificationInfo info =
|
||||
new MBeanNotificationInfo(types, name, description);
|
||||
return new MBeanNotificationInfo[]{info};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSocketPort() {
|
||||
return socketPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSocketPort(int socketPort) {
|
||||
int oldPort = this.socketPort;
|
||||
this.socketPort = socketPort;
|
||||
|
||||
Notification n = new AttributeChangeNotification(this, sequenceNumber++,
|
||||
System.currentTimeMillis(), "Socket Port changed", "socketPort", "int",
|
||||
oldPort, this.socketPort);
|
||||
sendNotification(n);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSslPort() {
|
||||
return sslPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSslPort(int sslPort) {
|
||||
int oldPort = this.sslPort;
|
||||
this.sslPort = sslPort;
|
||||
|
||||
Notification n = new AttributeChangeNotification(this, sequenceNumber++,
|
||||
System.currentTimeMillis(), "SSL Port changed", "sslPort", "int",
|
||||
oldPort, this.sslPort);
|
||||
sendNotification(n);
|
||||
}
|
||||
|
||||
public String getServer_ip() {
|
||||
return server_ip;
|
||||
}
|
||||
|
||||
public void setServer_ip(String server_ip) {
|
||||
this.server_ip = server_ip;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package net.petafuel.fuelifints.management;
|
||||
|
||||
public interface CommunicationManagementMBean {
|
||||
boolean isNioMode();
|
||||
void setNioMode(boolean nioMode);
|
||||
|
||||
int getSocketPort();
|
||||
void setSocketPort(int socketPort);
|
||||
|
||||
int getSslPort();
|
||||
void setSslPort(int sslPort);
|
||||
}
|
||||
236
src/main/java/net/petafuel/fuelifints/model/Dialog.java
Normal file
236
src/main/java/net/petafuel/fuelifints/model/Dialog.java
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
package net.petafuel.fuelifints.model;
|
||||
|
||||
import net.petafuel.fuelifints.communication.FinTSCommunicationHandler;
|
||||
import net.petafuel.fuelifints.model.client.ClientProductInfo;
|
||||
import net.petafuel.fuelifints.model.client.LegitimationInfo;
|
||||
import net.petafuel.fuelifints.model.client.TransactionInfo;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Hashalgorithmus;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Dialog {
|
||||
|
||||
private FinTSCommunicationHandler.CommunicationChannel communicationChannel;
|
||||
private ArrayList<Message> messages = new ArrayList<Message>();
|
||||
private Message currentMessage;
|
||||
private int taskId;
|
||||
private String dialogId;
|
||||
private long timeStamp;
|
||||
private boolean lastMessage; //Gibt an, ob das serverseitig die letzte Nachricht ist (FinTS 3: HKEND)
|
||||
private SecurityMethod securityMethod;
|
||||
private String bankId;
|
||||
private String userId;
|
||||
private int keyVersion;
|
||||
private int keyNumber;
|
||||
private LegitimationInfo legitimationsInfo = new LegitimationInfo();
|
||||
private ClientProductInfo clientProductInfo;
|
||||
private Integer messageNumber = 1;
|
||||
private TransactionInfo transactionInfo;
|
||||
private ErrorInfo errorInfo;
|
||||
private String sicherheitsKontrollReferenz;
|
||||
|
||||
public Dialog() {
|
||||
//generiere zufällige, neue DialogId:
|
||||
SecureRandom random = new SecureRandom();
|
||||
this.dialogId = new BigInteger(130, random).toString(32);
|
||||
//legitimationsInfo = new LegitimationInfo();
|
||||
clientProductInfo = new ClientProductInfo();
|
||||
errorInfo = new ErrorInfo();
|
||||
timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fügt dem Dialog eine neue Nachricht hinzu.
|
||||
* Diese Nachricht wird automatisch auch als aktuelle Nachricht (currentMessage) markiert
|
||||
*
|
||||
* @param message Nachricht, die dem Dialog hinzugefügt werden soll
|
||||
*/
|
||||
public void addMessage(Message message) {
|
||||
updateTimeStamp();
|
||||
if (!this.messages.contains(message)) {
|
||||
this.messages.add(message);
|
||||
this.setCurrentMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert die Dialog Id des Dialogs zurück
|
||||
*
|
||||
* @return Dialog Id des Dialog
|
||||
*/
|
||||
public String getDialogId() {
|
||||
return dialogId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt die Dialog Id des Dialogs auf den übergebenen Wert
|
||||
*
|
||||
* @param dialogId Neue Dialog Id, die im Dialog gesetzt werden soll
|
||||
*/
|
||||
public void setDialogId(String dialogId) {
|
||||
updateTimeStamp();
|
||||
this.dialogId = dialogId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zwei Dialog Objekte sind gleich, wenn ihre Dialog Ids übereinstimmen
|
||||
*
|
||||
* @param o Objekt, das mit dem aktuellen Dialog verglichen werden soll
|
||||
* @return true, wenn das Vergleichobjekt auch ein Dialog ist und die Dialog Ids übereinstimmen, ansonsten false
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof Dialog)) return false;
|
||||
|
||||
Dialog dialog = (Dialog) o;
|
||||
|
||||
if (dialogId != null ? !dialogId.equals(dialog.dialogId) : dialog.dialogId != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return dialogId != null ? dialogId.hashCode() : 0;
|
||||
}
|
||||
|
||||
public int getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public void setTaskId(int taskId) {
|
||||
this.taskId = taskId;
|
||||
updateTimeStamp();
|
||||
}
|
||||
|
||||
public Message getCurrentMessage() {
|
||||
return currentMessage;
|
||||
}
|
||||
|
||||
public void setCurrentMessage(Message currentMessage) {
|
||||
updateTimeStamp();
|
||||
this.currentMessage = currentMessage;
|
||||
}
|
||||
|
||||
public String getBankId() {
|
||||
return bankId;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public int getKeyVersion() {
|
||||
return keyVersion;
|
||||
}
|
||||
|
||||
public int getKeyNumber() {
|
||||
return keyNumber;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public void setBankId(String bankId) {
|
||||
if (this.bankId != null || bankId == null) {
|
||||
return;
|
||||
}
|
||||
this.bankId = bankId;
|
||||
}
|
||||
|
||||
public void setLegitimationInfo(LegitimationInfo legitimationInfo) {
|
||||
this.legitimationsInfo = legitimationInfo;
|
||||
}
|
||||
|
||||
public LegitimationInfo getLegitimationsInfo() {
|
||||
return legitimationsInfo;
|
||||
}
|
||||
|
||||
public ClientProductInfo getClientProductInfo() {
|
||||
return clientProductInfo;
|
||||
}
|
||||
|
||||
public void setClientProductInfo(ClientProductInfo clientProductInfo) {
|
||||
this.clientProductInfo = clientProductInfo;
|
||||
}
|
||||
|
||||
public Integer getMessageNumber() {
|
||||
return messageNumber;
|
||||
}
|
||||
|
||||
public void setMessageNumber(Integer messageNumber) {
|
||||
this.messageNumber = messageNumber;
|
||||
}
|
||||
|
||||
public void increaseMessageNumber() {
|
||||
messageNumber++;
|
||||
}
|
||||
|
||||
public void setTransactionInfo(TransactionInfo transactionInfo) {
|
||||
this.transactionInfo = transactionInfo;
|
||||
}
|
||||
|
||||
public TransactionInfo getTransactionInfo() {
|
||||
return transactionInfo;
|
||||
}
|
||||
|
||||
public ErrorInfo getErrorInfo() {
|
||||
return errorInfo;
|
||||
}
|
||||
|
||||
public void setErrorInfo(ErrorInfo errorInfo) {
|
||||
this.errorInfo = errorInfo;
|
||||
}
|
||||
|
||||
public FinTSCommunicationHandler.CommunicationChannel getCommunicationChannel() {
|
||||
return communicationChannel;
|
||||
}
|
||||
|
||||
public void setCommunicationChannel(FinTSCommunicationHandler.CommunicationChannel communicationChannel) {
|
||||
this.communicationChannel = communicationChannel;
|
||||
switch (communicationChannel) {
|
||||
case SSL:
|
||||
legitimationsInfo.setSecurityMethod(SecurityMethod.PIN_1);
|
||||
legitimationsInfo.setHashalgorithmus(new Hashalgorithmus("1:999:1".getBytes()));
|
||||
break;
|
||||
case SOCKET:
|
||||
if (legitimationsInfo.getSecurityMethod() == null) {
|
||||
legitimationsInfo.setSecurityMethod(SecurityMethod.RDH_10);
|
||||
}
|
||||
legitimationsInfo.setHashalgorithmus(new Hashalgorithmus("1:6:1".getBytes()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLastMessage() {
|
||||
return lastMessage;
|
||||
}
|
||||
|
||||
public void setLastMessage(boolean lastMessage) {
|
||||
this.lastMessage = lastMessage;
|
||||
}
|
||||
|
||||
public String getSicherheitsKontrollReferenz() {
|
||||
return sicherheitsKontrollReferenz;
|
||||
}
|
||||
|
||||
public void setSicherheitsKontrollReferenz(String sicherheitsKontrollReferenz) {
|
||||
this.sicherheitsKontrollReferenz = sicherheitsKontrollReferenz;
|
||||
}
|
||||
|
||||
private void updateTimeStamp() {
|
||||
timeStamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public long getTimeStamp() {
|
||||
if(transactionInfo != null) {
|
||||
updateTimeStamp();
|
||||
}
|
||||
return timeStamp;
|
||||
}
|
||||
}
|
||||
25
src/main/java/net/petafuel/fuelifints/model/ErrorInfo.java
Normal file
25
src/main/java/net/petafuel/fuelifints/model/ErrorInfo.java
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package net.petafuel.fuelifints.model;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMS;
|
||||
|
||||
public class ErrorInfo {
|
||||
|
||||
private boolean errorOccured = false;
|
||||
private HIRMS errorSegment;
|
||||
|
||||
public boolean isErrorOccured() {
|
||||
return errorOccured;
|
||||
}
|
||||
|
||||
public void setErrorOccured(boolean errorOccured) {
|
||||
this.errorOccured = errorOccured;
|
||||
}
|
||||
|
||||
public HIRMS getErrorSegment() {
|
||||
return errorSegment;
|
||||
}
|
||||
|
||||
public void setErrorSegment(HIRMS errorSegment) {
|
||||
this.errorSegment = errorSegment;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package net.petafuel.fuelifints.model;
|
||||
|
||||
public interface IDependentElement {
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package net.petafuel.fuelifints.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IExecutableElement {
|
||||
|
||||
public static enum StatusCode {
|
||||
OK, INFO, WARNING, ERROR
|
||||
}
|
||||
|
||||
public StatusCode execute(Dialog dialog);
|
||||
|
||||
public List<IMessageElement> getReplyMessageElements();
|
||||
|
||||
public IMessageElement getStatusElement();
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package net.petafuel.fuelifints.model;
|
||||
|
||||
import net.petafuel.fuelifints.exceptions.ElementParseException;
|
||||
import net.petafuel.fuelifints.exceptions.HBCIValidationException;
|
||||
|
||||
/**
|
||||
* Dieses Interface liefert die Basismethoden, die für jedes Nachrichtenelement nötig sind.
|
||||
*/
|
||||
public interface IMessageElement {
|
||||
|
||||
public byte[] getBytes();
|
||||
public void parseElement() throws ElementParseException;
|
||||
public boolean validate() throws HBCIValidationException;
|
||||
}
|
||||
126
src/main/java/net/petafuel/fuelifints/model/Message.java
Normal file
126
src/main/java/net/petafuel/fuelifints/model/Message.java
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
package net.petafuel.fuelifints.model;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMS;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.Segment;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Message {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(Message.class);
|
||||
|
||||
private int messageNumber;
|
||||
private String messageId;
|
||||
private int taskId;
|
||||
private List<IMessageElement> messageElements;
|
||||
private SecurityMethod securityMethod;
|
||||
private String userId;
|
||||
private String bankId;
|
||||
private int segmentCount;
|
||||
private List<IMessageElement> replyElements = new ArrayList<>();
|
||||
|
||||
public Message(int taskId, List<IMessageElement> messageElements, String dialogId) {
|
||||
this.taskId = taskId;
|
||||
this.messageElements = messageElements;
|
||||
this.messageId = dialogId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Message{" +
|
||||
"messageId=" + messageId +
|
||||
", messageNumber=" + messageNumber +
|
||||
'}';
|
||||
}
|
||||
|
||||
public String getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
public void executeGVs() {
|
||||
|
||||
}
|
||||
|
||||
public List<IMessageElement> getMessageElements() {
|
||||
return messageElements;
|
||||
}
|
||||
|
||||
public int getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public void setTaskId(int taskId) {
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public void setSecurityMethod(SecurityMethod securityMethod) {
|
||||
this.securityMethod = securityMethod;
|
||||
}
|
||||
|
||||
public SecurityMethod getSecurityMethod() {
|
||||
return securityMethod;
|
||||
}
|
||||
|
||||
public byte[] getMessageBytes() {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
LOG.debug("IMessageElementsSize: {}", messageElements.size());
|
||||
for (int i = 0; i < messageElements.size(); i++) {
|
||||
IMessageElement messageElement = messageElements.get(i);
|
||||
if (messageElement != null) {
|
||||
try {
|
||||
byteArrayOutputStream.write(((Segment) messageElement).getHbciEncoded());
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException ex) {
|
||||
LOG.error("IOException during creating bytes of message..", ex);
|
||||
return new byte[0];
|
||||
}
|
||||
byteArrayOutputStream.write('\'');
|
||||
try {
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException e) {
|
||||
LOG.error("IOException during creating bytes of message..", e);
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setBankId(String bankId) {
|
||||
this.bankId = bankId;
|
||||
}
|
||||
|
||||
public String getBankId() {
|
||||
return bankId;
|
||||
}
|
||||
|
||||
public void setSegmentCount(int segmentCount) {
|
||||
this.segmentCount = segmentCount;
|
||||
}
|
||||
|
||||
public int getSegmentCount() {
|
||||
return segmentCount;
|
||||
}
|
||||
|
||||
public void addReplyElement(HIRMS hirms) {
|
||||
replyElements.add(hirms);
|
||||
}
|
||||
|
||||
public List<IMessageElement> getReplyElements() {
|
||||
return replyElements;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
package net.petafuel.fuelifints.model.client;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
|
||||
public class ClientProductInfo {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ClientProductInfo.class);
|
||||
|
||||
private String userSystemId;
|
||||
private Integer currentClientBPDVersion;
|
||||
private Integer currentClientUPDVersion;
|
||||
private Integer dialogLanguage;
|
||||
private String clientProductName;
|
||||
private String clientProductVersion;
|
||||
private boolean hksynRequired;
|
||||
|
||||
public void setUserSystemId(String userSystemId) {
|
||||
this.userSystemId = userSystemId;
|
||||
}
|
||||
|
||||
public String getUserSystemId() {
|
||||
return userSystemId;
|
||||
}
|
||||
|
||||
public void setCurrentClientBPDVersion(Integer currentClientBPDVersion) {
|
||||
this.currentClientBPDVersion = currentClientBPDVersion;
|
||||
}
|
||||
|
||||
public Integer getCurrentClientBPDVersion() {
|
||||
return currentClientBPDVersion;
|
||||
}
|
||||
|
||||
public void setCurrentClientUPDVersion(Integer currentClientUPDVersion) {
|
||||
this.currentClientUPDVersion = currentClientUPDVersion;
|
||||
}
|
||||
|
||||
public Integer getCurrentClientUPDVersion() {
|
||||
return currentClientUPDVersion;
|
||||
}
|
||||
|
||||
public void setDialogLanguage(Integer dialogLanguage) {
|
||||
this.dialogLanguage = dialogLanguage;
|
||||
}
|
||||
|
||||
public Integer getDialogLanguage() {
|
||||
return dialogLanguage;
|
||||
}
|
||||
|
||||
public void setClientProductName(String clientProductName) {
|
||||
this.clientProductName = clientProductName;
|
||||
}
|
||||
|
||||
public String getClientProductName() {
|
||||
return clientProductName;
|
||||
}
|
||||
|
||||
public void setClientProductVersion(String clientProductVersion) {
|
||||
this.clientProductVersion = clientProductVersion;
|
||||
}
|
||||
|
||||
public String getClientProductVersion() {
|
||||
return clientProductVersion;
|
||||
}
|
||||
|
||||
public void setHksynRequired() {
|
||||
hksynRequired = true;
|
||||
}
|
||||
|
||||
public void hksynRequested() {
|
||||
hksynRequired = false;
|
||||
}
|
||||
|
||||
public boolean hksynRequired() {
|
||||
return hksynRequired;
|
||||
}
|
||||
|
||||
public boolean validateClientProductInfo() {
|
||||
|
||||
if (this.clientProductName == null || this.clientProductName.equals("")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try (BufferedReader csvReader = new BufferedReader(new FileReader(System.getProperty("productinfo.csv.filepath")))) {
|
||||
String row;
|
||||
int startRow = Integer.parseInt(System.getProperty("productinfo.csv.startRow", "10"));
|
||||
int pointer = 0;
|
||||
while ((row = csvReader.readLine()) != null) {
|
||||
|
||||
// Anfang der CSV Datei überspringen
|
||||
if (pointer < startRow) {
|
||||
pointer++;
|
||||
continue;
|
||||
}
|
||||
|
||||
String[] data = row.split(";");
|
||||
|
||||
// Produktbezeichnung mit dem Eintrag in der Liste vergleichen
|
||||
if (this.clientProductName.equals(data[2])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException invalidIndex){
|
||||
LOG.error("Fehler beim Parsen der CSV-Datei - unerwartetes Format");
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
package net.petafuel.fuelifints.model.client;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Hashalgorithmus;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class LegitimationInfo {
|
||||
private static final Logger LOG = LogManager.getLogger(LegitimationInfo.class);
|
||||
public static final String CUSTOMER_ANONYM = "9999999999";
|
||||
|
||||
private SecurityMethod securityMethod;
|
||||
private String userId; //Benutzerkennung
|
||||
private String customerId; //Kunden-ID
|
||||
private String bankId;
|
||||
|
||||
protected String tanResponse;
|
||||
|
||||
private boolean userIdentified;
|
||||
private Hashalgorithmus hashalgorithmus;
|
||||
|
||||
private String sicherheitsfunktion = "2";
|
||||
|
||||
private boolean anonymousAccount = false;
|
||||
private boolean userKeysSubmitted = false;
|
||||
private boolean isStrongAuthenticated = false;
|
||||
|
||||
public LegitimationInfo() {
|
||||
|
||||
}
|
||||
|
||||
public LegitimationInfo(LegitimationInfo legitimationInfo) {
|
||||
this.securityMethod = legitimationInfo.securityMethod;
|
||||
this.userId = legitimationInfo.userId;
|
||||
this.customerId = legitimationInfo.customerId;
|
||||
this.bankId = legitimationInfo.bankId;
|
||||
this.userIdentified = legitimationInfo.userIdentified;
|
||||
this.hashalgorithmus = legitimationInfo.hashalgorithmus;
|
||||
this.sicherheitsfunktion = legitimationInfo.sicherheitsfunktion;
|
||||
this.anonymousAccount = legitimationInfo.anonymousAccount;
|
||||
this.userKeysSubmitted = legitimationInfo.userKeysSubmitted;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.anonymousAccount = userId.equals(CUSTOMER_ANONYM);
|
||||
LOG.debug("Setting new userId: {}", userId);
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserIdentified(boolean userIdentified) {
|
||||
this.userIdentified = userIdentified;
|
||||
}
|
||||
|
||||
public boolean isUserIdentified() {
|
||||
return userIdentified;
|
||||
}
|
||||
|
||||
public void setSecurityMethod(SecurityMethod securityMethod) {
|
||||
this.securityMethod = securityMethod;
|
||||
}
|
||||
|
||||
public SecurityMethod getSecurityMethod() {
|
||||
return securityMethod;
|
||||
}
|
||||
|
||||
public String getBankId() {
|
||||
return bankId;
|
||||
}
|
||||
|
||||
public void setBankId(String bankId) {
|
||||
this.bankId = bankId;
|
||||
}
|
||||
|
||||
public String getCustomerId() {
|
||||
return customerId;
|
||||
}
|
||||
|
||||
public void setCustomerId(String customerId) {
|
||||
this.anonymousAccount = customerId.equals(CUSTOMER_ANONYM);
|
||||
this.customerId = customerId;
|
||||
}
|
||||
|
||||
public void setHashalgorithmus(Hashalgorithmus hashalgorithmus) {
|
||||
this.hashalgorithmus = hashalgorithmus;
|
||||
}
|
||||
|
||||
public Hashalgorithmus getHashalgorithmus() {
|
||||
return hashalgorithmus;
|
||||
}
|
||||
|
||||
public String getSicherheitsfunktion() {
|
||||
return sicherheitsfunktion;
|
||||
}
|
||||
|
||||
public void setSicherheitsfunktion(String sicherheitsfunktion) {
|
||||
this.sicherheitsfunktion = sicherheitsfunktion;
|
||||
}
|
||||
|
||||
public boolean isAnonymousAccount() {
|
||||
return anonymousAccount;
|
||||
}
|
||||
|
||||
public boolean userKeysSubmitted() {
|
||||
return userKeysSubmitted;
|
||||
}
|
||||
|
||||
public void setUserKeysSubmitted(boolean submitted) {
|
||||
userKeysSubmitted = submitted;
|
||||
}
|
||||
|
||||
public void setTanResponse(String tanResponse) {
|
||||
this.tanResponse = tanResponse;
|
||||
}
|
||||
|
||||
public String getTanResponse() {
|
||||
return tanResponse;
|
||||
}
|
||||
|
||||
public boolean isStrongAuthenticated() {
|
||||
return isStrongAuthenticated;
|
||||
}
|
||||
|
||||
public void setStrongAuthenticated(boolean strongAuthenticated) {
|
||||
this.isStrongAuthenticated = strongAuthenticated;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package net.petafuel.fuelifints.model.client;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class TransactionInfo {
|
||||
|
||||
private byte[] auftragsHashwert;
|
||||
private Date gueltigkeitsDatum;
|
||||
private String auftragsreferenz;
|
||||
private String tanProzess;
|
||||
private String tanListennummer;
|
||||
private String challenge;
|
||||
private List<String> parameterChallengeKlasse;
|
||||
private boolean tanUsed = false;
|
||||
|
||||
public byte[] getAuftragsHashwert() {
|
||||
return auftragsHashwert;
|
||||
}
|
||||
|
||||
public void setAuftragsHashwert(byte[] auftragsHashwert) {
|
||||
this.auftragsHashwert = auftragsHashwert;
|
||||
}
|
||||
|
||||
public Date getGueltigkeitsDatum() {
|
||||
return gueltigkeitsDatum;
|
||||
}
|
||||
|
||||
public void setGueltigkeitsDatum(Date gueltigkeitsDatum) {
|
||||
this.gueltigkeitsDatum = gueltigkeitsDatum;
|
||||
}
|
||||
|
||||
public String getAuftragsreferenz() {
|
||||
return auftragsreferenz;
|
||||
}
|
||||
|
||||
public void setAuftragsreferenz(String auftragsreferenz) {
|
||||
this.auftragsreferenz = auftragsreferenz;
|
||||
}
|
||||
|
||||
public String getTanProzess() {
|
||||
return tanProzess;
|
||||
}
|
||||
|
||||
public void setTanProzess(String tanProzess) {
|
||||
this.tanProzess = tanProzess;
|
||||
}
|
||||
|
||||
public void setTanListennummer(String tanListennummer) {
|
||||
this.tanListennummer = tanListennummer;
|
||||
}
|
||||
|
||||
public String getTanListennummer() {
|
||||
return tanListennummer;
|
||||
}
|
||||
|
||||
public void setChallenge(String challenge) {
|
||||
this.challenge = challenge;
|
||||
}
|
||||
|
||||
public String getChallenge() {
|
||||
return challenge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
TransactionInfo that = (TransactionInfo) o;
|
||||
|
||||
if (!Arrays.equals(auftragsHashwert, that.auftragsHashwert)) return false;
|
||||
if (auftragsreferenz != null ? !auftragsreferenz.equals(that.auftragsreferenz) : that.auftragsreferenz != null)
|
||||
return false;
|
||||
if (gueltigkeitsDatum != null ? !gueltigkeitsDatum.equals(that.gueltigkeitsDatum) : that.gueltigkeitsDatum != null)
|
||||
return false;
|
||||
if (tanListennummer != null ? !tanListennummer.equals(that.tanListennummer) : that.tanListennummer != null)
|
||||
return false;
|
||||
if (tanProzess != null ? !tanProzess.equals(that.tanProzess) : that.tanProzess != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = gueltigkeitsDatum != null ? gueltigkeitsDatum.hashCode() : 0;
|
||||
result = 31 * result + (auftragsreferenz != null ? auftragsreferenz.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<String> getParameterChallengeKlasse() {
|
||||
return parameterChallengeKlasse;
|
||||
}
|
||||
|
||||
public void setParameterChallengeKlasse(List<String> parameterChallengeKlasse) {
|
||||
this.parameterChallengeKlasse = parameterChallengeKlasse;
|
||||
}
|
||||
|
||||
public boolean isTanUsed() {
|
||||
return tanUsed;
|
||||
}
|
||||
|
||||
public void setTanUsed(boolean tanUsed) {
|
||||
this.tanUsed = tanUsed;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package net.petafuel.fuelifints.protocol;
|
||||
|
||||
/**
|
||||
* Klasse um die Informationen aus einer Clientnachricht zu speichern und an den entsprechenden FinTSController zur
|
||||
* weiteren Auswertung weiter zu reichen
|
||||
*/
|
||||
public class FinTSPayload {
|
||||
|
||||
private byte[] payload;
|
||||
private int taskId;
|
||||
|
||||
public FinTSPayload(byte[] payload, int taskId) {
|
||||
this.payload = payload;
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public int getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public void setTaskId(int taskId) {
|
||||
this.taskId = taskId;
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(byte[] payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package net.petafuel.fuelifints.protocol;
|
||||
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
|
||||
public interface IFinTSDecryptor extends Runnable {
|
||||
|
||||
public void setPayload(FinTSPayload payload);
|
||||
|
||||
public void setDialog(Dialog dialog);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package net.petafuel.fuelifints.protocol;
|
||||
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
|
||||
public interface IFinTSEncryptor extends Runnable{
|
||||
|
||||
public void setDialog(Dialog dialog);
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package net.petafuel.fuelifints.protocol;
|
||||
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.Message;
|
||||
|
||||
public interface IFinTSExecutor extends Runnable {
|
||||
|
||||
public Message execute();
|
||||
|
||||
public void setDialog(Dialog dialog);
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package net.petafuel.fuelifints.protocol;
|
||||
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
|
||||
/**
|
||||
* FFTS-27 - Kann raus!
|
||||
*/
|
||||
public interface IFinTSInjector extends Runnable {
|
||||
public void setDialog(Dialog dialog);
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package net.petafuel.fuelifints.protocol;
|
||||
|
||||
import net.petafuel.fuelifints.HBCIParseException;
|
||||
import net.petafuel.fuelifints.exceptions.DeprecatedVersionHKTAN;
|
||||
import net.petafuel.fuelifints.exceptions.HBCIValidationException;
|
||||
import net.petafuel.fuelifints.exceptions.UnregisteredClientProduct;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
|
||||
public interface IFinTSParser extends Runnable {
|
||||
|
||||
public void setPayload(FinTSPayload payload);
|
||||
|
||||
public void setDialog(Dialog dialog);
|
||||
|
||||
public void parseAndValidateRequest(int taskId, byte[] request) throws HBCIParseException, SegmentNotSupportedException, HBCIValidationException, DeprecatedVersionHKTAN, UnregisteredClientProduct;
|
||||
|
||||
public String getDialogId();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package net.petafuel.fuelifints.protocol;
|
||||
|
||||
import net.petafuel.fuelifints.FinTSServer;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
|
||||
public interface IFinTSReplyThread extends Runnable {
|
||||
|
||||
public void setDialog(Dialog dialog);
|
||||
|
||||
public void setFinTSServer(FinTSServer finTSServer);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package net.petafuel.fuelifints.protocol;
|
||||
|
||||
public class SegmentNotSupportedException extends Exception {
|
||||
|
||||
public SegmentNotSupportedException(String segmentName) {
|
||||
super(segmentName + " not supported");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,479 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3;
|
||||
|
||||
import net.petafuel.fuelifints.ExecutorManager;
|
||||
import net.petafuel.fuelifints.FinTSServer;
|
||||
import net.petafuel.fuelifints.HBCIParseException;
|
||||
import net.petafuel.fuelifints.IFinTSController;
|
||||
import net.petafuel.fuelifints.communication.FinTSCommunicationHandler;
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacade;
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacadeManager;
|
||||
import net.petafuel.fuelifints.dataaccess.dataobjects.PinParameterObject;
|
||||
import net.petafuel.fuelifints.exceptions.DependencyResolveException;
|
||||
import net.petafuel.fuelifints.management.CommunicationManagement;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.model.Message;
|
||||
import net.petafuel.fuelifints.model.client.LegitimationInfo;
|
||||
import net.petafuel.fuelifints.model.client.TransactionInfo;
|
||||
import net.petafuel.fuelifints.protocol.FinTSPayload;
|
||||
import net.petafuel.fuelifints.protocol.fints3.annotations.ApplicantAccount;
|
||||
import net.petafuel.fuelifints.protocol.fints3.annotations.Requires;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMG;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMS;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNHBK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNHBS;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.SegmentUtil;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Bezugsnachricht;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungInternational;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungNational;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Rueckmeldung;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.support.ByteSplit;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.jce.provider.JDKMessageDigest;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class FinTS3Controller implements IFinTSController {
|
||||
|
||||
private final long dialogTimeout;
|
||||
private static final Logger LOG = LogManager.getLogger(FinTS3Controller.class);
|
||||
|
||||
private final List<Dialog> runningDialogs = new ArrayList<Dialog>();
|
||||
private static FinTS3Controller ourInstance;
|
||||
private ExecutorManager executor = new ExecutorManager();
|
||||
|
||||
private DataAccessFacade accessFacade;
|
||||
private FinTSServer finTSServer;
|
||||
|
||||
private Thread dialogCleanupThread;
|
||||
|
||||
/**
|
||||
* private (Singleton) Constructor
|
||||
*/
|
||||
private FinTS3Controller() {
|
||||
dialogTimeout = Long.parseLong(System.getProperty(CommunicationManagement.DIALOG_TIMEOUT_MILLIS, "10000"));
|
||||
dialogCleanupThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!Thread.interrupted()) {
|
||||
try {
|
||||
Thread.sleep(2 * 60 * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
//ignored
|
||||
}
|
||||
synchronized (runningDialogs) {
|
||||
int countBefore = runningDialogs.size();
|
||||
Iterator<Dialog> iterator = runningDialogs.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Dialog dialog = iterator.next();
|
||||
if ((System.currentTimeMillis() - dialog.getTimeStamp()) > dialogTimeout) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
if (countBefore != runningDialogs.size()) {
|
||||
LOG.debug("cleaned up {} Dialog(s)", (countBefore - runningDialogs.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogCleanupThread.setDaemon(true);
|
||||
dialogCleanupThread.setName("DialogCleanupThread");
|
||||
dialogCleanupThread.start();
|
||||
}
|
||||
|
||||
public static FinTS3Controller getInstance() {
|
||||
if (ourInstance == null)
|
||||
ourInstance = new FinTS3Controller();
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Für Tests, um nach dem Test die Insatnz vom FinTSController los zu werden.
|
||||
*/
|
||||
public static void removeInstance() {
|
||||
ourInstance = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean newRequest(final FinTSPayload payload, FinTSCommunicationHandler.CommunicationChannel channel) {
|
||||
//Dialog ID holen, neue Message erstellen, neue oder existierenden Dialog suchen
|
||||
String dialogId = "0";
|
||||
Integer nachrichtenNummer = 1;
|
||||
try {
|
||||
//Dialog ID steht in HNHBK, Element Nummer 4:
|
||||
List<byte[]> segments = ByteSplit.split(payload.getPayload(), ByteSplit.MODE_SEGMENT);
|
||||
if (segments.size() > 0) {
|
||||
HNHBK hnhbk = new HNHBK(segments.get(0));
|
||||
hnhbk.parseElement();
|
||||
dialogId = hnhbk.getDialogId();
|
||||
nachrichtenNummer = hnhbk.getNachrichtennummer();
|
||||
|
||||
Message requestMessage = new Message(payload.getTaskId(), new ArrayList<IMessageElement>(), hnhbk.getDialogId());
|
||||
Dialog dialog = getNewOrExistingDialog(hnhbk.getDialogId());
|
||||
|
||||
dialog.setCommunicationChannel(channel);
|
||||
dialog.addMessage(requestMessage);
|
||||
LOG.info(dialog);
|
||||
/*
|
||||
if (dialog.getMessageNumber() != 1 && (dialog.getMessageNumber() != hnhbk.getNachrichtennummer() - 1)) {
|
||||
replyWithError(payload.getTaskId(), "9010::Unbekannter Nachrichtenaufbau");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
dialog.setMessageNumber(hnhbk.getNachrichtennummer());
|
||||
FinTS3Decryptor decryptor = new FinTS3Decryptor();
|
||||
this.executor.addToDecryptionQueue(dialog, payload, decryptor);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Interner Fehler", e);
|
||||
}
|
||||
|
||||
HNHBK hnhbk = new HNHBK(new byte[0]);
|
||||
hnhbk.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HNHBK.class).setSegmentVersion(3).setSegmentNumber(1).build());
|
||||
hnhbk.setDialog_id(dialogId);
|
||||
hnhbk.setNachrichtennummer(nachrichtenNummer);
|
||||
hnhbk.setBezugsnachricht(new Bezugsnachricht((dialogId + ":" + nachrichtenNummer).getBytes()));
|
||||
hnhbk.setNachrichtengroesse("012345678901");
|
||||
hnhbk.setHbci_version(300);
|
||||
HIRMG hirmg = new HIRMG(new byte[0]);
|
||||
hirmg.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentVersion(2).setSegmentKennung(HIRMG.class).setSegmentNumber(2).build());
|
||||
hirmg.setRueckmeldung(Rueckmeldung.getRueckmeldung("9800"));
|
||||
HIRMS hirms = new HIRMS(new byte[0]);
|
||||
hirms.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentVersion(2).setSegmentKennung(HIRMS.class).setSegmentNumber(3).build());
|
||||
hirms.addRueckmeldung(Rueckmeldung.getRueckmeldung("9951"));
|
||||
HNHBS hnhbs = new HNHBS(new byte[0]);
|
||||
hnhbs.setNachrichtennummer(nachrichtenNummer);
|
||||
hnhbs.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentVersion(1).setSegmentNumber(4).setSegmentKennung(HNHBS.class).build());
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
byteArrayOutputStream.write(hnhbk.getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
byteArrayOutputStream.write(hirmg.getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
byteArrayOutputStream.write(hirms.getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
byteArrayOutputStream.write(hnhbs.getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException e) {
|
||||
//unrepairable error
|
||||
}
|
||||
|
||||
byte[] respondBytes = byteArrayOutputStream.toByteArray();
|
||||
int length = respondBytes.length;
|
||||
byte[] lengthBytes = String.format("%012d", length).getBytes();
|
||||
System.arraycopy(lengthBytes, 0, respondBytes, 10, 12);
|
||||
String responseString = "error";
|
||||
try {
|
||||
responseString = new String(respondBytes, "ISO-8859-1");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.error("Exception", e);
|
||||
}
|
||||
|
||||
Thread t = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
//Fehler beim Parsen der Dialog ID - Fehler zurückgeben, weitere Verarbeitung abbrechen
|
||||
replyWithError(payload.getTaskId(), getName());
|
||||
}
|
||||
};
|
||||
t.setName(responseString);
|
||||
t.start();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing purposes
|
||||
*
|
||||
* @param manager new Executormanager to be used
|
||||
*/
|
||||
@Override
|
||||
public void setExecutor(ExecutorManager manager) {
|
||||
this.executor = manager;
|
||||
}
|
||||
|
||||
private Dialog getNewOrExistingDialog(String requestId) throws HBCIParseException {
|
||||
if (requestId == null)
|
||||
throw new HBCIParseException("no dialogid given");
|
||||
if (requestId.equals("0")) {
|
||||
//Neue Nachricht, MessageId wurde bisher noch nicht gesetzt.
|
||||
Dialog newDialog = new Dialog();
|
||||
synchronized (runningDialogs) {
|
||||
runningDialogs.add(newDialog);
|
||||
}
|
||||
return newDialog;
|
||||
} else {
|
||||
synchronized (runningDialogs) {
|
||||
for (Dialog currentDialog : runningDialogs) {
|
||||
if (currentDialog.getDialogId().equals(requestId))
|
||||
return currentDialog;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new HBCIParseException("Unknown dialogId");
|
||||
}
|
||||
|
||||
private Dialog getExistingDialog(int taskId) {
|
||||
synchronized (runningDialogs) {
|
||||
for (Dialog currentDialog : runningDialogs) {
|
||||
if (currentDialog.getTaskId() == taskId)
|
||||
return currentDialog;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateDialog(Dialog dialog) {
|
||||
|
||||
}
|
||||
|
||||
public void updateLegitimationInfo(String requestId, LegitimationInfo legitimationInfo) {
|
||||
synchronized (runningDialogs) {
|
||||
for (Dialog currentDialog : runningDialogs) {
|
||||
if (currentDialog.getDialogId().equals(requestId))
|
||||
currentDialog.setLegitimationInfo(legitimationInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link net.petafuel.fuelifints.protocol.fints3.FinTS3Decryptor} when decrypting is done (iof necessary)
|
||||
*
|
||||
* @param payload {@link FinTSPayload} Object containing the decrypted payload
|
||||
*/
|
||||
@Override
|
||||
public void finishedDecryption(FinTSPayload payload, Dialog dialog) {
|
||||
FinTS3Parser parser = new FinTS3Parser();
|
||||
executor.addToParseQueue(dialog, payload, parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link net.petafuel.fuelifints.protocol.fints3.FinTS3Parser} when it finished its parsing
|
||||
*
|
||||
* @param taskId taskId of FinTS request
|
||||
* @param currentDialog
|
||||
*/
|
||||
@Override
|
||||
public void finishedParsing(int taskId, Dialog currentDialog) {
|
||||
LOG.trace("finishedParsing called; taskId: {}", taskId);
|
||||
currentDialog.setTaskId(taskId);
|
||||
if (currentDialog.getCurrentMessage().getUserId() != null) {
|
||||
currentDialog.setUserId(currentDialog.getCurrentMessage().getUserId());
|
||||
}
|
||||
currentDialog.setBankId(currentDialog.getCurrentMessage().getBankId());
|
||||
executor.addToExecuteQueue(currentDialog, new FinTS3Executor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectDependencies(IMessageElement elem, Dialog dialog) throws DependencyResolveException {
|
||||
LOG.debug("Injecting dependencies for {}", elem.getClass().getSimpleName());
|
||||
// Inject dependencies into elem
|
||||
if (dialog == null) {
|
||||
throw new DependencyResolveException("Dialog nicht vorhanden.");
|
||||
}
|
||||
if (dialog.getLegitimationsInfo() == null) {
|
||||
throw new DependencyResolveException("Legitimationsinfo nicht gesetzt.");
|
||||
}
|
||||
if (dialog.getClientProductInfo() == null) {
|
||||
throw new DependencyResolveException("ClientProductInfo nicht gesetzt.");
|
||||
}
|
||||
|
||||
//zu Beginn die Requirement durchgehen und prüfen
|
||||
if (elem.getClass().getAnnotation(Requires.class) != null) {
|
||||
DataAccessFacade dataAccessFacade = DataAccessFacadeManager.getAccessFacade(dialog.getBankId());
|
||||
Requires.Requirement[] requirements = elem.getClass().getAnnotation(Requires.class).value();
|
||||
for (Requires.Requirement requirement : requirements) {
|
||||
switch (requirement) {
|
||||
case EXECUTION_ALLOWED: //Prüft, ob die Ausführung des Segments für den angemeldeten Benutzer erlaubt ist
|
||||
String accountId = "";
|
||||
for (Field f : elem.getClass().getDeclaredFields()) {
|
||||
//Gehe alle Felder durch, um zu schauen, ob eventuell eine Auftraggeberkontonummer gesetzt ist:
|
||||
if (f.getAnnotation(ApplicantAccount.class) != null) {
|
||||
f.setAccessible(true);
|
||||
try {
|
||||
Object o = f.get(elem);
|
||||
if (o != null) {
|
||||
if (o instanceof KontoverbindungNational)
|
||||
accountId = ((KontoverbindungNational) o).getKontonummer();
|
||||
else if (o instanceof KontoverbindungInternational)
|
||||
accountId = SegmentUtil.ibanToAccountNr(((KontoverbindungInternational) o).getIban());
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
LOG.error("Problem accessing " + f.getName() + " in Element " + elem.getClass().getSimpleName());
|
||||
throw new DependencyResolveException("Auftrag konnte aus technischen Gründen nicht verarbeitet werden.", "9999");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if ((!accountId.equals("") && !dataAccessFacade.operationAllowedForAccount(dialog.getLegitimationsInfo(), accountId, elem.getClass()))
|
||||
|| !dataAccessFacade.operationAllowedForAccount(dialog.getLegitimationsInfo(), elem.getClass())) {
|
||||
throw new DependencyResolveException("Benutzer hat keine Auftragsberechtigung", "9380");
|
||||
}
|
||||
break;
|
||||
case TAN: //Prüfe, ob die Ausführung eine TAN benötigt und wenn ja, ob die transactioninfos stimmen:
|
||||
PinParameterObject ppo = dataAccessFacade.getPinParameter();
|
||||
|
||||
// TAN ist nur erforderlich falls
|
||||
// 1. Das Segment TAN erfordert und
|
||||
// 2. der Kunde noch nicht stark authenifiziert wurde
|
||||
if (ppo.isTanErforderlich(elem.getClass().getSimpleName()) && !dialog.getLegitimationsInfo().isStrongAuthenticated()) {
|
||||
//für diesen Geschäftsvorfall wird eine TAN benötigt
|
||||
if (dialog.getLegitimationsInfo().getSecurityMethod() == SecurityMethod.PIN_1 || dialog.getLegitimationsInfo().getSecurityMethod() == SecurityMethod.PIN_2) {
|
||||
|
||||
TransactionInfo transactionInfo = dialog.getTransactionInfo();
|
||||
if (transactionInfo == null)
|
||||
throw new DependencyResolveException("Verarbeitung nicht möglich", "9010");
|
||||
String hashalgorithmus = dialog.getLegitimationsInfo().getHashalgorithmus().getHashalgorithmus();
|
||||
byte[] generatedHashFromSegment = new byte[0];
|
||||
//das Abschließende Semikolon fehlt
|
||||
byte[] segmentBytes = new byte[elem.getBytes().length + 1];
|
||||
System.arraycopy(elem.getBytes(), 0, segmentBytes, 0, elem.getBytes().length);
|
||||
segmentBytes[elem.getBytes().length] = '\'';
|
||||
if (hashalgorithmus.equals("999")) {
|
||||
//RIPEMD-160
|
||||
JDKMessageDigest.RIPEMD160 digest = new JDKMessageDigest.RIPEMD160();
|
||||
generatedHashFromSegment = digest.digest(segmentBytes);
|
||||
} else if (hashalgorithmus.equals("1")) {
|
||||
//SHA-1
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
generatedHashFromSegment = digest.digest(segmentBytes);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
//never thrown SHA-1 is supported
|
||||
}
|
||||
}
|
||||
if (!Arrays.equals(transactionInfo.getAuftragsHashwert(), generatedHashFromSegment)) {
|
||||
LOG.error("Auftragshashwert stimmt nicht mit errechnetem Hashwert überein");
|
||||
LOG.error("Die Überweisung wird abgelehnt");
|
||||
throw new DependencyResolveException("Verarbeitung nicht möglich", "9010");
|
||||
}
|
||||
transactionInfo.setTanUsed(true);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case KUNDENSYSTEM_ID:
|
||||
String userSystemId = dialog.getClientProductInfo().getUserSystemId();
|
||||
if (userSystemId == null || (userSystemId.equals("0") && !dialog.getLegitimationsInfo().isAnonymousAccount())) {
|
||||
throw new DependencyResolveException("Kundensystem-Id fehlerhaft oder nicht vorhanden: '" + userSystemId + "'");
|
||||
}
|
||||
break;
|
||||
case USER_IDENTIFIED:
|
||||
if (!dialog.getLegitimationsInfo().isUserIdentified()) {
|
||||
throw new DependencyResolveException("Nutzer nicht identifiziert.");
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//setze benötigte Attribute
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void finishedInjecting(int taskId) {
|
||||
Dialog currentDialog = getExistingDialog(taskId);
|
||||
if (currentDialog == null) {
|
||||
}
|
||||
executor.addToExecuteQueue(currentDialog, new FinTS3Executor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link Dialog) after execution of FinTS request is finished
|
||||
*
|
||||
* @param taskId taskId of FinTS request
|
||||
*/
|
||||
@Override
|
||||
public void finishedExecuting(Message msg) {
|
||||
LOG.trace("finishedExecuting called; taskId: {}", msg.getTaskId());
|
||||
Dialog currentDialog = getExistingDialog(msg.getTaskId());
|
||||
if (currentDialog == null) {
|
||||
LOG.error("Dialog konnte nicht gefunden werden.");
|
||||
replyWithError(msg.getTaskId(), "Could not find dialog.");
|
||||
} else {
|
||||
currentDialog.setCurrentMessage(msg);
|
||||
FinTS3Encryptor finTS3Encryptor = new FinTS3Encryptor();
|
||||
finTS3Encryptor.setDialog(currentDialog);
|
||||
executor.addToEncryptionQueue(currentDialog, finTS3Encryptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishedEncryption(Message msg) {
|
||||
LOG.trace("finishedEncryption called; taskId: {}", msg.getTaskId());
|
||||
Dialog currentDialog = getExistingDialog(msg.getTaskId());
|
||||
if (currentDialog == null) {
|
||||
LOG.error("Dialog konnte nicht gefunden werden.");
|
||||
replyWithError(msg.getTaskId(), "Could not find dialog.");
|
||||
return;
|
||||
}
|
||||
|
||||
currentDialog.addMessage(msg);
|
||||
FinTS3ReplyThread replyThread = new FinTS3ReplyThread();
|
||||
executor.addToReplyQueue(currentDialog, finTSServer, replyThread);
|
||||
|
||||
}
|
||||
|
||||
public void replyWithError(int taskId, HIRMS hirms) {
|
||||
Dialog dialog = getExistingDialog(taskId);
|
||||
if (dialog != null && hirms != null) {
|
||||
List<IMessageElement> messageElements = new LinkedList<IMessageElement>();
|
||||
messageElements.add(hirms);
|
||||
Message errorMessage = new Message(taskId, messageElements, dialog.getDialogId());
|
||||
dialog.setCurrentMessage(errorMessage);
|
||||
dialog.addMessage(errorMessage);
|
||||
FinTS3Encryptor encryptor = new FinTS3Encryptor();
|
||||
encryptor.setDialog(dialog);
|
||||
executor.addToEncryptionQueue(dialog, encryptor);
|
||||
}
|
||||
}
|
||||
|
||||
public void replyWithError(int taskid, String error) {
|
||||
if (error != null && finTSServer != null) {
|
||||
finTSServer.respond(taskid, error.getBytes(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRunningDialogCount() {
|
||||
synchronized (runningDialogs) {
|
||||
return runningDialogs.size();
|
||||
}
|
||||
}
|
||||
|
||||
public void setAccessFacade(DataAccessFacade accessFacade) {
|
||||
this.accessFacade = accessFacade;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFinTSServer(FinTSServer finTSServer) {
|
||||
this.finTSServer = finTSServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinTSServer getFinTSServer() {
|
||||
return this.finTSServer;
|
||||
}
|
||||
|
||||
public ExecutorManager getExecutorManager() {
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3;
|
||||
|
||||
import net.petafuel.fuelifints.cryptography.Cryptography;
|
||||
import net.petafuel.fuelifints.cryptography.CryptographyFactory;
|
||||
import net.petafuel.fuelifints.exceptions.ElementParseException;
|
||||
import net.petafuel.fuelifints.exceptions.HBCISyntaxException;
|
||||
import net.petafuel.fuelifints.exceptions.HBCIValidationException;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.protocol.FinTSPayload;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSDecryptor;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNHBK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNHBS;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNVSD;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNVSK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.SegmentUtil;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Sicherheitsprofil;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Verschluesselungsalgorithmus;
|
||||
import net.petafuel.fuelifints.support.ByteSplit;
|
||||
import net.petafuel.fuelifints.support.LogHelper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* - prüft die Syntax der Steuersegmente
|
||||
* - entschlüsselt die Nachricht
|
||||
* - prüft die Signatur
|
||||
* <p/>
|
||||
* Diese Klasse tastet die eigentlichen Aufträge nicht an, das wird später vom Parser erledigt
|
||||
*/
|
||||
public class FinTS3Decryptor implements IFinTSDecryptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(FinTS3Decryptor.class);
|
||||
private FinTSPayload payload;
|
||||
private Dialog dialog;
|
||||
private HNHBK hnhbk;
|
||||
private HNHBS hnhbs;
|
||||
private HNVSK hnvsk;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//3 Schritte:
|
||||
//Nachrichtenkopf & Nachrichtenabschluss prüfen (HNHBK & HNHBS) FIXED
|
||||
//Verschlüsselungskopf prüfen (HNVSK) -> später irgendwann bei RDH auch entschlüsseln FIXED
|
||||
//Signatur überprüfen (HNSHK, HNSHA) -> für RDH den Hashwert checken (später), für PIN/TAN die PIN, ev. TAN checken WONT-FIX
|
||||
//
|
||||
//Diese Logik steckt zur Zeit noch (teilweise) in protocol.fints3.segments.SegmentManager und muss da raus
|
||||
|
||||
List<byte[]> segments = null;
|
||||
try {
|
||||
segments = ByteSplit.split(payload.getPayload(), ByteSplit.MODE_SEGMENT);
|
||||
} catch (HBCISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
try {
|
||||
LOG.trace("Anzahl segmente: " + segments.size() + " von Auftrag:");
|
||||
for (byte[] seg : segments) {
|
||||
LOG.trace(LogHelper.removeSignatureInformation(new String(seg, "ISO-8859-1")));
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
}
|
||||
boolean messageSizeValid = false;
|
||||
try {
|
||||
messageSizeValid = messageSizeValid || checkMessageSize(segments.get(0));
|
||||
} catch (ElementParseException e) {
|
||||
LOG.error("ElementParseException", e);
|
||||
}
|
||||
|
||||
if (messageSizeValid) {
|
||||
LOG.trace("MessageSize valid");
|
||||
} else {
|
||||
LOG.error("MessageSize invalid", new HBCIValidationException("Nachrichtenlänge ungültig."));
|
||||
throw new RuntimeException(new HBCIValidationException("Nachrichtenlänge ungültig."));
|
||||
}
|
||||
|
||||
try {
|
||||
checkHnhbk();
|
||||
} catch (HBCIValidationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
boolean messageNumberValid = false;
|
||||
try {
|
||||
messageNumberValid = messageNumberValid || checkHnhbs(segments.get(segments.size() - 1));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.error("UnsupportedEncodingException", e);
|
||||
throw new RuntimeException(e);
|
||||
} catch (ElementParseException e) {
|
||||
LOG.error("ElementParseException", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
if (messageNumberValid) {
|
||||
LOG.trace("MessageNumber valid");
|
||||
} else {
|
||||
LOG.error("MessageNumber invalid", new HBCIValidationException("Nachrichtenummer in HNHBK und HNHBS stimmen nicht überein."));
|
||||
throw new RuntimeException(new HBCIValidationException("Nachrichtenummer in HNHBK und HNHBS stimmen nicht überein."));
|
||||
}
|
||||
|
||||
if (SegmentUtil.getSegmentName(segments.get(1)).equals("HNVSK")) {
|
||||
/*
|
||||
* Verschlüsselte Nachricht erhalten.
|
||||
*/
|
||||
LOG.trace("Check if message is PinTan or HBCI (encrypted).");
|
||||
String securityMethod = "";
|
||||
try {
|
||||
securityMethod = getSecurityMethod(segments.get(1));
|
||||
} catch (ElementParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Cryptography cryptography = CryptographyFactory.getCryptography(SecurityMethod.valueOf(securityMethod.replace('-', '_')));
|
||||
byte[] encrypted = new byte[0];
|
||||
try {
|
||||
encrypted = getEncryptedBytes(segments.get(2));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
//ISO-8859-1 is supported
|
||||
} catch (ElementParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
byte[] decryptedSegments = cryptography.decrypt(encrypted, getCypherKey(securityMethod), hnvsk.getSchluesselname().getKreditsinstitutkennung().getKreditinstitutscode());
|
||||
LOG.trace("Finished decrypting...");
|
||||
dialog.setBankId(hnvsk.getSchluesselname().getKreditsinstitutkennung().getKreditinstitutscode());
|
||||
|
||||
try {
|
||||
LOG.trace("Decrypted Segments: {}", LogHelper.removeSignatureInformation(new String(decryptedSegments, "ISO-8859-1")));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.error("UnsupportedEncodingException", e);
|
||||
}
|
||||
|
||||
// + 2 weil das Segment-Trennzeichen (') in HNHBK und HNHBS abgeschnitten ist.
|
||||
int newPayloadLength = hnhbk.getBytes().length + hnhbs.getBytes().length + decryptedSegments.length + 2;
|
||||
byte[] newPayload = new byte[newPayloadLength];
|
||||
int offset = 0;
|
||||
System.arraycopy(hnhbk.getBytes(), 0, newPayload, offset, hnhbk.getBytes().length);
|
||||
offset += hnhbk.getBytes().length;
|
||||
newPayload[offset] = '\'';
|
||||
offset++;
|
||||
System.arraycopy(decryptedSegments, 0, newPayload, offset, decryptedSegments.length);
|
||||
offset += decryptedSegments.length;
|
||||
System.arraycopy(hnhbs.getBytes(), 0, newPayload, offset, hnhbs.getBytes().length);
|
||||
offset += hnhbs.getBytes().length;
|
||||
newPayload[offset] = '\'';
|
||||
|
||||
try {
|
||||
LOG.info("Auftragsnachricht: " + LogHelper.removeSignatureInformation(new String(newPayload, "ISO-8859-1")));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.error("UnsupportedEncodingException", e);
|
||||
}
|
||||
|
||||
payload = new FinTSPayload(newPayload, payload.getTaskId());
|
||||
|
||||
} else {
|
||||
//anonyme anfragen müsse nicht angefasst werden -> payload unverändert weiter reichen
|
||||
}
|
||||
FinTS3Controller.getInstance().finishedDecryption(payload, dialog);
|
||||
}
|
||||
|
||||
private byte[] getEncryptedBytes(byte[] bytes) throws UnsupportedEncodingException, ElementParseException {
|
||||
//String hnvsdString = new String(bytes,0,bytes.length-1,"ISO-8859-1");
|
||||
HNVSD hnvsd = new HNVSD(bytes);
|
||||
hnvsd.parseElement();
|
||||
byte[] encryptedDE = hnvsd.getVerschluesselteDaten();
|
||||
//LOG.debug("EncryptedDE: " + new String(encryptedDE, "ISO-8859-1"));
|
||||
int offset = 1;
|
||||
for (; offset < encryptedDE.length; offset++) {
|
||||
if (encryptedDE[offset] == 0x40) {
|
||||
LOG.trace("Found binary character at: {}", offset);
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
byte[] data = new byte[encryptedDE.length - offset];
|
||||
LOG.trace("EncryptedDataLength: {}", data.length);
|
||||
System.arraycopy(encryptedDE, offset, data, 0, data.length);
|
||||
return data;
|
||||
}
|
||||
|
||||
private byte[] getCypherKey(String securityMethod) {
|
||||
if (securityMethod.equals("PIN-1") || securityMethod.equals("PIN-2")) {
|
||||
/*
|
||||
* Daten in HNVSD werden hier nicht verschlüsselt.
|
||||
*/
|
||||
return new byte[0];
|
||||
} else {
|
||||
Verschluesselungsalgorithmus verschluesselungsalgorithmus = hnvsk.getVerschluesselungsalgorithmus();
|
||||
byte[] keyDEG = verschluesselungsalgorithmus.getWertAlgorithmusparameterSchluessel();
|
||||
//LOG.debug(new String(keyDEG));
|
||||
int index = 1;
|
||||
for (; index < keyDEG.length; index++) {
|
||||
if (keyDEG[index] == 0x40) {
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] encryptedKey = new byte[keyDEG.length - index];
|
||||
System.arraycopy(keyDEG, index, encryptedKey, 0, encryptedKey.length);
|
||||
return encryptedKey;
|
||||
}
|
||||
}
|
||||
|
||||
private String getSecurityMethod(byte[] bytes) throws ElementParseException {
|
||||
//String hnvskString = new String(bytes,0,bytes.length-1,"ISO-8859-1");
|
||||
hnvsk = new HNVSK(bytes);
|
||||
hnvsk.parseElement();
|
||||
Sicherheitsprofil sicherheitsprofil = hnvsk.getSicherheitsprofil();
|
||||
return sicherheitsprofil.getSicherheitsverfahren() + "-" + sicherheitsprofil.getSicherheitsverfahrensversion();
|
||||
}
|
||||
|
||||
private void checkHnhbk() throws HBCIValidationException {
|
||||
if (hnhbk != null) {
|
||||
int nachrichtennummer = hnhbk.getNachrichtennummer();
|
||||
if (nachrichtennummer <= 0) {
|
||||
HBCIValidationException exception = new HBCIValidationException("Nachrichtennummer <= 0.");
|
||||
LOG.error("Nachrichtennummer falsch.", exception);
|
||||
throw exception;
|
||||
}
|
||||
if (hnhbk.getBezugsnachricht() != null) {
|
||||
LOG.error("Bezugsnachricht vom Kunden gesetzt. Abbruch.", new HBCIValidationException("Bezugsnachricht vom Kunden gesetzt. Abbruch."));
|
||||
throw new HBCIValidationException("Bezugsnachricht vom Kunden gesetzt. Abbruch.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkHnhbs(byte[] segment) throws UnsupportedEncodingException, ElementParseException {
|
||||
//String hnhbsString = new String(segment,0,segment.length-1,"ISO-8859-1");
|
||||
//LOG.info(hnhbsString);
|
||||
hnhbs = new HNHBS(segment);
|
||||
hnhbs.parseElement();
|
||||
int nachrichtennummerHnhbk = hnhbk.getNachrichtennummer();
|
||||
int nachrichtennummerHnhbs = hnhbs.getNachrichtennummer();
|
||||
LOG.trace("Nachrichtennummer HNHBK: " + nachrichtennummerHnhbk + " Nachrichtennummer HNHBS: " + nachrichtennummerHnhbs);
|
||||
return nachrichtennummerHnhbk == nachrichtennummerHnhbs;
|
||||
}
|
||||
|
||||
private boolean checkMessageSize(byte[] segment) throws ElementParseException {
|
||||
//String hnhbkSting = new String(segment,0,segment.length-1,"ISO-8859-1");
|
||||
//LOG.info(hnhbkSting);
|
||||
hnhbk = new HNHBK(segment);
|
||||
hnhbk.parseElement();
|
||||
String messageSize = hnhbk.getNachrichtengroesse();
|
||||
//int payloadSize = (new String(payload.getPayload(),"ISO-8859-1")).length();
|
||||
//LOG.info("Parsed MessageSize: "+ messageSize +" parsed int: "+ Integer.parseInt(messageSize)+ " payload size: "+ payloadSize);
|
||||
return Integer.parseInt(messageSize) == payload.getPayload().length/*(new String(payload.getPayload(),"ISO-8859-1")).length()*/;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPayload(FinTSPayload payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public Dialog getDialog() {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public void setDialog(Dialog dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3;
|
||||
|
||||
import net.petafuel.fuelifints.cryptography.Cryptography;
|
||||
import net.petafuel.fuelifints.cryptography.CryptographyFactory;
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacade;
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacadeManager;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.model.Message;
|
||||
import net.petafuel.fuelifints.model.client.ClientProductInfo;
|
||||
import net.petafuel.fuelifints.model.client.LegitimationInfo;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSEncryptor;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.AbstractElement;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMG;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMS;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNVSD;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNVSK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Rueckmeldung;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Schluesselname;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.SicherheitsdatumUndUhrzeit;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Sicherheitsidentifikationsdetails;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Sicherheitsprofil;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Verschluesselungsalgorithmus;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Verschlüsselt die Antwortnachrichten.
|
||||
* Fügt die Segmente HNVSK und HNVSD dazu und füllt diese entsprechend.
|
||||
*/
|
||||
public class FinTS3Encryptor implements IFinTSEncryptor {
|
||||
private static final Logger LOG = LogManager.getLogger(FinTS3Encryptor.class);
|
||||
|
||||
private Dialog dialog;
|
||||
|
||||
@Override
|
||||
public void setDialog(Dialog dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (dialog.getLegitimationsInfo().isAnonymousAccount()/* || dialog.getLegitimationsInfo().userKeysSubmitted()*/) {
|
||||
/*
|
||||
* Anonyme Nachricht erhalten, keine verschlüsselung nötig.
|
||||
*/
|
||||
dialog.getLegitimationsInfo().setUserKeysSubmitted(false);
|
||||
FinTS3Controller.getInstance().finishedEncryption(dialog.getCurrentMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
SecurityMethod securityMethod = dialog.getLegitimationsInfo().getSecurityMethod();
|
||||
LOG.debug("Encrypting with securitymethod: {}", securityMethod);
|
||||
Cryptography cryptography = CryptographyFactory.getCryptography(securityMethod);
|
||||
|
||||
Message message = dialog.getCurrentMessage();
|
||||
byte[] encryptionKey = cryptography.generateKey();
|
||||
|
||||
LOG.debug("EncryptionKey length: {}", encryptionKey.length);
|
||||
|
||||
byte[] toEncrypt = message.getMessageBytes();
|
||||
LOG.debug("ToEncryptLength: {}, ToEncrypt: {}", toEncrypt.length, new String(toEncrypt));
|
||||
byte[] encryptedMessage = cryptography.encryptMessage(toEncrypt, encryptionKey, dialog.getBankId());
|
||||
LOG.debug("encryptedMessageLength: {}", encryptedMessage.length);
|
||||
byte[] encryptedKey = cryptography.encryptEncryptionKey(encryptionKey, dialog.getBankId(), dialog.getUserId());
|
||||
if (encryptedKey.length == 0) {
|
||||
//Fehler
|
||||
List<IMessageElement> elements = new LinkedList<IMessageElement>();
|
||||
|
||||
HIRMG hirmg = new HIRMG(new byte[0]);
|
||||
hirmg.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMG.class).setSegmentNumber(2).setSegmentVersion(2).build());
|
||||
hirmg.setRueckmeldung(Rueckmeldung.getRueckmeldung("9999"));
|
||||
elements.add(hirmg);
|
||||
HIRMS hirms = new HIRMS(new byte[0]);
|
||||
hirms.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentVersion(2).setSegmentNumber(3).setSegmentKennung(HIRMS.class).build());
|
||||
Rueckmeldung rueckmeldung = new Rueckmeldung(new byte[0]);
|
||||
rueckmeldung.setRueckmeldungscode("9999");
|
||||
rueckmeldung.setRueckmeldungstext("Bei der Verarbeitung ist ein Fehler aufgetreten.");
|
||||
hirms.addRueckmeldung(rueckmeldung);
|
||||
elements.add(hirms);
|
||||
|
||||
Message message1 = new Message(message.getTaskId(), elements, dialog.getDialogId());
|
||||
message1.setSegmentCount(message.getSegmentCount());
|
||||
FinTS3Controller.getInstance().finishedEncryption(message1);
|
||||
return;
|
||||
}
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
byteArrayOutputStream.write('@');
|
||||
byteArrayOutputStream.write(Integer.toString(encryptedMessage.length).getBytes("ISO-8859-1"));
|
||||
byteArrayOutputStream.write('@');
|
||||
byteArrayOutputStream.write(encryptedMessage);
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
HNVSD hnvsd = new HNVSD(new byte[0]);
|
||||
//hnvsd.setSegmentkopf(new Segmentkopf("HNVSD:999:1".getBytes()));
|
||||
hnvsd.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HNVSD.class).setSegmentNumber(999).setSegmentVersion(1).build());
|
||||
hnvsd.setVerschluesselteDaten(byteArrayOutputStream.toByteArray());
|
||||
List<IMessageElement> elements = new LinkedList<IMessageElement>();
|
||||
elements.add(hnvsd);
|
||||
|
||||
HNVSK hnvsk = new HNVSK(new byte[0]);
|
||||
//hnvsk.setSegmentkopf(new Segmentkopf("HNVSK:998:3".getBytes()));
|
||||
hnvsk.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HNVSK.class).setSegmentNumber(998).setSegmentVersion(3).build());
|
||||
|
||||
Sicherheitsprofil sicherheitsprofil = new Sicherheitsprofil(securityMethod.getHbciDEG());
|
||||
hnvsk.setSicherheitsprofil(sicherheitsprofil);
|
||||
if (securityMethod == SecurityMethod.PIN_1 || securityMethod == SecurityMethod.PIN_2)
|
||||
hnvsk.setSicherheitsfunktion("998");
|
||||
else
|
||||
hnvsk.setSicherheitsfunktion("4");
|
||||
hnvsk.setSicherheitslieferant("1");
|
||||
DataAccessFacade dataAccessFacade = DataAccessFacadeManager.getAccessFacade(dialog.getBankId());
|
||||
ClientProductInfo clientProductInfo = dialog.getClientProductInfo();
|
||||
LegitimationInfo legitimationInfo = dialog.getLegitimationsInfo();
|
||||
|
||||
String userSystemId = null;
|
||||
try {
|
||||
userSystemId = dataAccessFacade == null ? "0" : dataAccessFacade.getUserSystemId(dialog.getDialogId(), legitimationInfo, clientProductInfo);
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
Sicherheitsidentifikationsdetails sicherheitsidentifikationsdetails = new Sicherheitsidentifikationsdetails(("2::" + (userSystemId == null ? 0 : userSystemId)).getBytes());
|
||||
hnvsk.setSicherheitsidentifikationsdetails(sicherheitsidentifikationsdetails);
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd:HHmmss");
|
||||
GregorianCalendar gregorianCalendar = (GregorianCalendar) GregorianCalendar.getInstance();
|
||||
SicherheitsdatumUndUhrzeit sicherheitsdatumUndUhrzeit = new SicherheitsdatumUndUhrzeit(("1:" + simpleDateFormat.format(gregorianCalendar.getTime())).getBytes());
|
||||
hnvsk.setSicherheitsdatumUndUhrzeit(sicherheitsdatumUndUhrzeit);
|
||||
byteArrayOutputStream.reset();
|
||||
try {
|
||||
byteArrayOutputStream.write('2');
|
||||
byteArrayOutputStream.write(':');
|
||||
byteArrayOutputStream.write(getHbciFormat(securityMethod.getOperationsModusVerschluesselung()));
|
||||
byteArrayOutputStream.write(':');
|
||||
byteArrayOutputStream.write(getHbciFormat(securityMethod.getVerschluesselungsAlgorithmus()));
|
||||
byteArrayOutputStream.write(':');
|
||||
byteArrayOutputStream.write('@');
|
||||
byteArrayOutputStream.write(Integer.toString(encryptedKey.length).getBytes());
|
||||
byteArrayOutputStream.write('@');
|
||||
byteArrayOutputStream.write(encryptedKey);
|
||||
byteArrayOutputStream.write(":6:1".getBytes());
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
Verschluesselungsalgorithmus verschluesselungsalgorithmus = new Verschluesselungsalgorithmus(byteArrayOutputStream.toByteArray());
|
||||
hnvsk.setVerschluesselungsalgorithmus(verschluesselungsalgorithmus);
|
||||
String userId = dialog.getLegitimationsInfo().getUserId();
|
||||
if (userId != null) {
|
||||
if (userId.isEmpty() && !dialog.getUserId().isEmpty()) {
|
||||
userId = dialog.getUserId();
|
||||
}
|
||||
} else {
|
||||
userId = "0";
|
||||
}
|
||||
|
||||
Schluesselname schluesselname = new Schluesselname(("280:" + dialog.getBankId() + ":" + AbstractElement.generateEscapedVersion(userId) + ":V:" + securityMethod.getVersionNumber() + ":1").getBytes());
|
||||
|
||||
hnvsk.setSchluesselname(schluesselname);
|
||||
hnvsk.setKomprimierungsfunktion("0");
|
||||
|
||||
elements.add(0, hnvsk);
|
||||
Message message1 = new Message(message.getTaskId(), elements, dialog.getDialogId());
|
||||
message1.setSegmentCount(message.getSegmentCount());
|
||||
FinTS3Controller.getInstance().finishedEncryption(message1);
|
||||
}
|
||||
|
||||
private byte[] getHbciFormat(int hbciCode) {
|
||||
return Integer.toString(hbciCode).getBytes(StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,342 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3;
|
||||
|
||||
import net.petafuel.fuelifints.cryptography.SignatureHelper;
|
||||
import net.petafuel.fuelifints.cryptography.SignatureHelperFactory;
|
||||
import net.petafuel.fuelifints.exceptions.DependencyResolveException;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.IDependentElement;
|
||||
import net.petafuel.fuelifints.model.IExecutableElement;
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.model.Message;
|
||||
import net.petafuel.fuelifints.model.client.LegitimationInfo;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSExecutor;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIISA;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMG;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMS;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHA;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.Segment;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Rueckmeldung;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Schluesselname;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.SicherheitsdatumUndUhrzeit;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Sicherheitsidentifikationsdetails;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Sicherheitsprofil;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Signaturalgorithmus;
|
||||
import net.petafuel.fuelifints.support.SegmentComparator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
public class FinTS3Executor implements IFinTSExecutor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(FinTS3Executor.class);
|
||||
|
||||
private Dialog dialog;
|
||||
|
||||
@Override
|
||||
public Message execute() {
|
||||
//iterate through last requests' segments to find gvs and their dependencies:
|
||||
|
||||
Message msg = this.dialog.getCurrentMessage();
|
||||
List<IMessageElement> messageElements = msg.getMessageElements();
|
||||
|
||||
//AntwortSegmente
|
||||
List<IMessageElement> replyElements = msg.getReplyElements();
|
||||
|
||||
boolean successful = false;
|
||||
boolean warning = false;
|
||||
boolean error = false;
|
||||
|
||||
/* Prüfe, dass bisher kein Fehler aufgetreten ist.
|
||||
* Fehler können an dieser Stelle bereits beim Entschlüsseln, der Signaturprüfung und beim Parsen der Segmente aufgetreten sein
|
||||
*/
|
||||
if (dialog.getErrorInfo() != null && !dialog.getErrorInfo().isErrorOccured()) {
|
||||
for (IMessageElement currentElement : messageElements) {
|
||||
if (currentElement instanceof IDependentElement) {// This segment has dependencies
|
||||
try {
|
||||
FinTS3Controller.getInstance().injectDependencies(currentElement, this.dialog);
|
||||
} catch (DependencyResolveException e) {
|
||||
LOG.error("DependencyResolveException", e);
|
||||
HIRMS hirms = new HIRMS(new byte[0]);
|
||||
hirms.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMS.class).setSegmentVersion(2).setBezugssegment(((Segment) currentElement).getSegmentkopf().getSegmentNummer()).build());
|
||||
Rueckmeldung rueckmeldung = new Rueckmeldung(new byte[0]);
|
||||
rueckmeldung.setRueckmeldungscode("9000");
|
||||
rueckmeldung.setRueckmeldungstext("Verarbeitung nicht möglich");
|
||||
hirms.addRueckmeldung(rueckmeldung);
|
||||
if (e.getErrorCode() != null && !e.getErrorCode().equals("")) {
|
||||
Rueckmeldung exceptionMeldung = new Rueckmeldung(new byte[0]);
|
||||
exceptionMeldung.setRueckmeldungscode(e.getErrorCode());
|
||||
exceptionMeldung.setRueckmeldungstext(e.getMessage());
|
||||
hirms.addRueckmeldung(exceptionMeldung);
|
||||
}
|
||||
replyElements.add(hirms);
|
||||
error = true;
|
||||
successful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gehe über alle Auftrag-Segmente und führe sie aus.
|
||||
* Jedes ausführbare Segment liefert einen StatusCode zurück der angibt,
|
||||
* ob die Ausführung erfolgreich, Warnungen enthielt oder fehlerhaft war.
|
||||
*
|
||||
* Falls ein Fehler aufgetreten ist, dann wird abgebrochen, bei Warnungen kann
|
||||
* weiter gearbeitet werden.
|
||||
*/
|
||||
if (currentElement instanceof IExecutableElement) {
|
||||
|
||||
IExecutableElement.StatusCode statusCode = ((IExecutableElement) currentElement).execute(dialog);
|
||||
List<IMessageElement> segmentReplyElements = ((IExecutableElement) currentElement).getReplyMessageElements();
|
||||
LOG.info("adding new reply element for element " + currentElement.getClass().getSimpleName() + " replyElement " + segmentReplyElements);
|
||||
if (segmentReplyElements != null && segmentReplyElements.size() > 0) {
|
||||
replyElements.addAll(segmentReplyElements);
|
||||
}
|
||||
switch (statusCode) {
|
||||
case OK:
|
||||
successful = true;
|
||||
break;
|
||||
case INFO:
|
||||
//INFO kann wie WARNING behandelt werden..
|
||||
case WARNING:
|
||||
warning = true;
|
||||
break;
|
||||
case ERROR:
|
||||
LOG.error("could not execute: {}", currentElement);
|
||||
if (currentElement != null && ((IExecutableElement) currentElement).getStatusElement() != null)
|
||||
LOG.error("error message: {}", new String(((IExecutableElement) currentElement).getStatusElement().getBytes()));
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
//füge alle Statuselemente hinzu, sie werden später sortiert.
|
||||
IMessageElement statusElement = ((IExecutableElement) currentElement).getStatusElement();
|
||||
if (statusElement != null && ((HIRMS) statusElement).getRueckmeldung() != null) {
|
||||
replyElements.add(statusElement);
|
||||
}
|
||||
if (error) {
|
||||
//Abbruch?
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error = true;
|
||||
if (dialog.getErrorInfo().getErrorSegment() != null) {
|
||||
replyElements.add(dialog.getErrorInfo().getErrorSegment());
|
||||
}
|
||||
}
|
||||
//erstelle HIRMG anhand der bisherigen Rückmeldungen
|
||||
HIRMG hirmg = buildHIRMG(successful, warning, error);
|
||||
replyElements.add(0, hirmg);
|
||||
|
||||
|
||||
return new Message(msg.getTaskId(), replyElements, msg.getMessageId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDialog(Dialog dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Message message = this.execute();
|
||||
|
||||
//HIRMS Segmente müssen zu Beginn der Nachricht stehen (jedoch nach HIRMG)
|
||||
List<IMessageElement> replySegments = message.getMessageElements();
|
||||
Collections.sort(replySegments, new SegmentComparator());
|
||||
|
||||
boolean containsHiisa = false;
|
||||
for (IMessageElement messageElement : replySegments) {
|
||||
if (messageElement instanceof HIISA) {
|
||||
containsHiisa = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!containsHiisa && dialog.getLegitimationsInfo().isAnonymousAccount() && dialog.getLegitimationsInfo().getSecurityMethod() != SecurityMethod.PIN_1 && dialog.getLegitimationsInfo().getSecurityMethod() != SecurityMethod.PIN_2) {
|
||||
//keine Bankschlüssel und Anonymer Dialog
|
||||
//es wird keine Signatur benötigt
|
||||
setSegmentNumbers(replySegments, 2);
|
||||
|
||||
message.setSegmentCount(replySegments.size() + 1);
|
||||
FinTS3Controller.getInstance().finishedExecuting(message);
|
||||
return;
|
||||
}
|
||||
|
||||
LegitimationInfo legitimationInfo = dialog.getLegitimationsInfo();
|
||||
if (legitimationInfo.getCustomerId() != null && legitimationInfo.isAnonymousAccount() && (legitimationInfo.getSecurityMethod() == SecurityMethod.PIN_1 || legitimationInfo.getSecurityMethod() == SecurityMethod.PIN_2) || (dialog.getErrorInfo() != null && dialog.getErrorInfo().isErrorOccured())) {
|
||||
//es wird keine Signatur benötigt, alle Segmente beginnen bei Nummer 2 (anonym PIN/TAN)
|
||||
setSegmentNumbers(replySegments, 2);
|
||||
} else {
|
||||
//es wird eine Signatur benötigt, alle Segmente beginnen bei Nummer 3
|
||||
setSegmentNumbers(replySegments, 3);
|
||||
createSignature(replySegments);
|
||||
}
|
||||
message.setSegmentCount(replySegments.size() + 1);
|
||||
FinTS3Controller.getInstance().finishedExecuting(message);
|
||||
}
|
||||
|
||||
private void setSegmentNumbers(List<IMessageElement> replySegments, int startNumber) {
|
||||
for (IMessageElement iMessageElement : replySegments) {
|
||||
Field[] fields = iMessageElement.getClass().getDeclaredFields();
|
||||
Field segmentkopfField = null;
|
||||
for (Field f : fields) {
|
||||
f.setAccessible(true);
|
||||
if (f.getType().equals(Segmentkopf.class)) {
|
||||
segmentkopfField = f;
|
||||
}
|
||||
}
|
||||
if (segmentkopfField == null) {
|
||||
throw new RuntimeException("could not set Segmentnumber.");
|
||||
} else {
|
||||
try {
|
||||
Segmentkopf segmentkopf = (Segmentkopf) segmentkopfField.get(iMessageElement);
|
||||
|
||||
segmentkopf.setSegmentNummer(startNumber++);
|
||||
} catch (IllegalAccessException e) {
|
||||
//setAccessible(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HIRMG buildHIRMG(boolean successful, boolean warning, boolean error) {
|
||||
HIRMG hirmg = new HIRMG(new byte[0]);
|
||||
Segmentkopf segmentkopf;// = new Segmentkopf("HIRMG:0:2".getBytes());
|
||||
segmentkopf = Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMG.class).setSegmentVersion(2).build();
|
||||
hirmg.setSegmentkopf(segmentkopf);
|
||||
try {
|
||||
Rueckmeldung rueckmeldung;
|
||||
if (successful && warning) {
|
||||
//3000er HIRMG
|
||||
rueckmeldung = new Rueckmeldung("3060::Teilweise liegen Warnungen oder Hinweise vor.".getBytes("ISO-8859-1"));
|
||||
} else if (successful && error) {
|
||||
//9000er HIRMG
|
||||
rueckmeldung = new Rueckmeldung("9910::Die Nachricht konnte nicht ausgeführt werden.".getBytes("ISO-8859-1"));
|
||||
} else if (!successful && !warning && error) {
|
||||
//9000er HIRMG
|
||||
rueckmeldung = new Rueckmeldung("9910::Die Nachricht konnte nicht ausgeführt werden.".getBytes("ISO-8859-1"));
|
||||
} else if (!successful && (warning | error)) {
|
||||
//3000er HIRMG
|
||||
rueckmeldung = new Rueckmeldung("3920::Es liegen Warnungen oder Fehler vor.".getBytes("ISO-8859-1"));
|
||||
} else {
|
||||
//0000er HIRMG
|
||||
rueckmeldung = new Rueckmeldung("0010::Auftrag erfolgreich entgegengenommen.".getBytes("ISO-8859-1"));
|
||||
}
|
||||
hirmg.setRueckmeldung(rueckmeldung);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
//ISO-8859-1 is supported
|
||||
}
|
||||
return hirmg;
|
||||
}
|
||||
|
||||
//TODO generieren von Segmente besser anpassen
|
||||
private void createSignature(List<IMessageElement> messageElements) {
|
||||
Segmentkopf segmentkopf;
|
||||
/*
|
||||
HIRMG hirmg = new HIRMG(new byte[0]);
|
||||
segmentkopf = new Segmentkopf("HIRMG:3:2".getBytes());
|
||||
Rueckmeldung rueckmeldung = new Rueckmeldung(new byte[0]);
|
||||
rueckmeldung.setRueckmeldungscode("0010");
|
||||
rueckmeldung.setRueckmeldungstext("Nachricht fehlerfrei entgegengenommen.");
|
||||
hirmg.setSegmentkopf(segmentkopf);
|
||||
hirmg.setRueckmeldung(rueckmeldung);
|
||||
messageElements.add(0, hirmg);
|
||||
*/
|
||||
SecurityMethod securityMethod = dialog.getLegitimationsInfo().getSecurityMethod();
|
||||
LOG.debug(dialog.getLegitimationsInfo().getSecurityMethod());
|
||||
if (securityMethod == null) {
|
||||
securityMethod = SecurityMethod.RDH_10;
|
||||
}
|
||||
SignatureHelper signatureHelper = SignatureHelperFactory.getSignatureHelper(securityMethod);
|
||||
dialog.setSicherheitsKontrollReferenz(String.valueOf((int) Math.abs(Math.random() * Integer.MAX_VALUE)));
|
||||
String sicherheitskontrollreferenz = dialog.getSicherheitsKontrollReferenz();
|
||||
HNSHK hnshk = new HNSHK(new byte[0]);
|
||||
//segmentkopf = new Segmentkopf("HNSHK:2:4".getBytes());
|
||||
segmentkopf = Segmentkopf.Builder.newInstance().setSegmentKennung(HNSHK.class).setSegmentNumber(2).setSegmentVersion(4).build();
|
||||
hnshk.setSegmentkopf(segmentkopf);
|
||||
Sicherheitsprofil sicherheitsprofil = new Sicherheitsprofil(securityMethod.getHbciDEG());
|
||||
hnshk.setSicherheitsprofil(sicherheitsprofil);
|
||||
hnshk.setSicherheitsfunktion(dialog.getLegitimationsInfo().getSicherheitsfunktion());
|
||||
hnshk.setSicherheitskontrollreferenz(sicherheitskontrollreferenz);
|
||||
hnshk.setSicherheitsapplikationskontrollbereich("1");
|
||||
hnshk.setSicherheitslieferantenrolle("1");
|
||||
Sicherheitsidentifikationsdetails sicherheitsidentifikationsdetails = new Sicherheitsidentifikationsdetails("2".getBytes());
|
||||
hnshk.setSicherheitsidentifikationsdetails(sicherheitsidentifikationsdetails);
|
||||
hnshk.setSicherheitsreferenznummer(1000);
|
||||
GregorianCalendar gregorianCalendar = (GregorianCalendar) GregorianCalendar.getInstance();
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd:HHmmss");
|
||||
SicherheitsdatumUndUhrzeit sicherheitsdatumUndUhrzeit = new SicherheitsdatumUndUhrzeit(("1:" + simpleDateFormat.format(gregorianCalendar.getTime())).getBytes());
|
||||
hnshk.setSicherheitsdatumUndUhrzeit(sicherheitsdatumUndUhrzeit);
|
||||
|
||||
if (securityMethod == SecurityMethod.PIN_1 || securityMethod == SecurityMethod.PIN_2) {
|
||||
hnshk.setHashalgorithmus(dialog.getLegitimationsInfo().getHashalgorithmus());
|
||||
Schluesselname schluesselname = new Schluesselname(("280:" + dialog.getBankId() + ":100:S:0:0").getBytes()); //Default Schlüsselname für PIN/TAN Kommunikation
|
||||
hnshk.setSchluesselname(schluesselname);
|
||||
hnshk.setSignaturalgorithmus(new Signaturalgorithmus("6:10:16".getBytes()));
|
||||
} else {
|
||||
hnshk.setHashalgorithmus(dialog.getLegitimationsInfo().getHashalgorithmus());
|
||||
Schluesselname schluesselname = new Schluesselname(("280:" + dialog.getBankId() + ":0:S:1:1").getBytes()); //TODO Schlüsselname aus der facade
|
||||
hnshk.setSchluesselname(schluesselname);
|
||||
hnshk.setSignaturalgorithmus(new Signaturalgorithmus("6:10:19".getBytes()));
|
||||
}
|
||||
|
||||
int segmentcount = 3;
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
byteArrayOutputStream.write(hnshk.getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
for (IMessageElement iMessageElement : messageElements) {
|
||||
if (iMessageElement != null) {
|
||||
segmentcount++;
|
||||
byteArrayOutputStream.write(((Segment) iMessageElement).getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
}
|
||||
}
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException ex) {
|
||||
|
||||
}
|
||||
|
||||
byte[] toSign = byteArrayOutputStream.toByteArray();
|
||||
|
||||
try {
|
||||
LOG.debug("toSign: {}", new String(toSign, "ISO-8859-1"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.error("UnsupportedEncodingException", e);
|
||||
}
|
||||
|
||||
HNSHA hnsha = new HNSHA(new byte[0]);
|
||||
//segmentkopf = new Segmentkopf(("HNSHA:" + (segmentcount) + ":2").getBytes());
|
||||
segmentkopf = Segmentkopf.Builder.newInstance().setSegmentKennung(HNSHA.class).setSegmentNumber(segmentcount).setSegmentVersion(2).build();
|
||||
hnsha.setSegmentkopf(segmentkopf);
|
||||
hnsha.setSicherheitskontrollreferenz(sicherheitskontrollreferenz);
|
||||
byte[] signature = signatureHelper.sign(toSign, hnshk);
|
||||
if (signature != null) {
|
||||
byteArrayOutputStream.reset();
|
||||
try {
|
||||
byteArrayOutputStream.write('@');
|
||||
for (char s : Integer.toString(signature.length).toCharArray()) {
|
||||
byteArrayOutputStream.write(s);
|
||||
}
|
||||
byteArrayOutputStream.write('@');
|
||||
byteArrayOutputStream.write(signature);
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
hnsha.setValidierungsresultat(byteArrayOutputStream.toByteArray());
|
||||
}
|
||||
messageElements.add(0, hnshk);
|
||||
messageElements.add(hnsha);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3;
|
||||
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSInjector;
|
||||
|
||||
/**
|
||||
* FFTS-27: Kann raus!
|
||||
*/
|
||||
@Deprecated
|
||||
public class FinTS3Injector implements IFinTSInjector {
|
||||
|
||||
private Dialog dialog;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
FinTS3Controller.getInstance().finishedInjecting(dialog.getTaskId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDialog(Dialog dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,313 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3;
|
||||
|
||||
import net.petafuel.fuelifints.HBCIParseException;
|
||||
import net.petafuel.fuelifints.cryptography.SignatureHelper;
|
||||
import net.petafuel.fuelifints.cryptography.SignatureHelperFactory;
|
||||
import net.petafuel.fuelifints.dataaccess.dataobjects.ReturnDataObject;
|
||||
import net.petafuel.fuelifints.exceptions.DeprecatedVersionHKTAN;
|
||||
import net.petafuel.fuelifints.exceptions.ElementParseException;
|
||||
import net.petafuel.fuelifints.exceptions.HBCIValidationException;
|
||||
import net.petafuel.fuelifints.exceptions.UnregisteredClientProduct;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.model.client.ClientProductInfo;
|
||||
import net.petafuel.fuelifints.model.client.LegitimationInfo;
|
||||
import net.petafuel.fuelifints.protocol.FinTSPayload;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSParser;
|
||||
import net.petafuel.fuelifints.protocol.SegmentNotSupportedException;
|
||||
import net.petafuel.fuelifints.protocol.fints3.model.SecurityMethod;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HIRMS;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HKIDN;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HKTAN;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HKVVB;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHA;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNSHK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.SegmentManager;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Rueckmeldung;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* - parsed die Auftragelemente (IMessageElement), die sich im Request befinden
|
||||
* <p/>
|
||||
* <p/>
|
||||
* Entschlüsselung und Verifizierung der Signatur erfolt nicht hier, sondern im IFinTSDecryptor
|
||||
* Es kann davon ausgegangen werden, dass die Nachricht fehlerfrei entschlüsselt und die Signatur verifiziert wurde
|
||||
*/
|
||||
|
||||
public class FinTS3Parser implements IFinTSParser, Runnable {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(FinTS3Parser.class);
|
||||
private Dialog dialog;
|
||||
private byte[] request;
|
||||
private ArrayList<IMessageElement> elements;
|
||||
private int taskId;
|
||||
private String dialogId = "";
|
||||
|
||||
public int getTaskId() {
|
||||
return this.taskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPayload(FinTSPayload payload) {
|
||||
this.request = payload.getPayload();
|
||||
this.taskId = payload.getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseAndValidateRequest(int taskId, byte[] request) throws HBCIParseException, SegmentNotSupportedException, HBCIValidationException, DeprecatedVersionHKTAN, UnregisteredClientProduct {
|
||||
|
||||
//split request in segment objects:
|
||||
this.elements = SegmentManager.getSegments(request);
|
||||
HNSHK hnshk = null;
|
||||
HNSHA hnsha = null;
|
||||
List<byte[]> signedSegments = new LinkedList<byte[]>();
|
||||
|
||||
boolean containsHKTAN = false;
|
||||
boolean containsHKIDN = false;
|
||||
boolean isClientMissingInformation = false;
|
||||
|
||||
for (IMessageElement messageElement : elements) {
|
||||
if (messageElement instanceof HKVVB) {
|
||||
boolean isValidClientProductInfo = false;
|
||||
try {
|
||||
((HKVVB) messageElement).parseElement();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Parsen von HKVVB für die Produktbezeichnung ist fehlgeschlagen.");
|
||||
}
|
||||
|
||||
String produktbezeichnung = ((HKVVB) messageElement).getProduktbezeichnung();
|
||||
|
||||
// Prüfung ob die Produktbezeichung registriert ist
|
||||
ClientProductInfo clientProductInfo = new ClientProductInfo();
|
||||
clientProductInfo.setClientProductName(produktbezeichnung);
|
||||
|
||||
isValidClientProductInfo = clientProductInfo.validateClientProductInfo();
|
||||
|
||||
LOG.info("Anfragendes Clientproduct {} ist gültig: {}", produktbezeichnung, isValidClientProductInfo);
|
||||
|
||||
// Falls die Prüfung nicht deaktiviert wurde und die Überprüfung fehlgeschlagen ist
|
||||
if (System.getProperty("productinfo.csv.check").equals("true") && ! isValidClientProductInfo) {
|
||||
throw new UnregisteredClientProduct();
|
||||
}
|
||||
}
|
||||
|
||||
if (messageElement instanceof HNSHK && ((HNSHK) messageElement).getSicherheitsfunktion().equals("999")) {
|
||||
isClientMissingInformation = true;
|
||||
}
|
||||
|
||||
if (messageElement instanceof HKIDN) {
|
||||
containsHKIDN = true;
|
||||
HKIDN hkidn = ((HKIDN) messageElement);
|
||||
dialog.setBankId(hkidn.getBankId());
|
||||
}
|
||||
|
||||
try {
|
||||
if(messageElement instanceof HKTAN) {
|
||||
containsHKTAN = true;
|
||||
if (((HKTAN) messageElement).getVersion() < 6) {
|
||||
throw new DeprecatedVersionHKTAN();
|
||||
}
|
||||
}
|
||||
} catch (ElementParseException e) {
|
||||
throw new HBCIParseException(e);
|
||||
}
|
||||
|
||||
if (messageElement instanceof HNSHK) {
|
||||
hnshk = (HNSHK) messageElement;
|
||||
dialog.setBankId(hnshk.getSchluesselname().getKreditsinstitutkennung().getKreditinstitutscode());
|
||||
}
|
||||
if (messageElement instanceof HNSHA) {
|
||||
hnsha = (HNSHA) messageElement;
|
||||
break;
|
||||
}
|
||||
//die Segmente zwischen HNSHK und HNVSK werden nur zur Signaturprüfung herangezogen
|
||||
//deshalb ist es an dieser Stelle möglich nachdem HNSHK gefunden wurde, alle Segmente
|
||||
//die anschließend folgen bis hin zu HNSHA in die Signaturprüfung mit aufzunehmen
|
||||
if (hnshk != null) {
|
||||
signedSegments.add(messageElement.getBytes());
|
||||
}
|
||||
}
|
||||
|
||||
LOG.info("Anonyme Anfrage: {}", dialog.getLegitimationsInfo().isAnonymousAccount());
|
||||
LOG.info("HKIDN vorhanden: {}", containsHKIDN);
|
||||
LOG.info("HKTAN vorhanden: {}", containsHKTAN);
|
||||
|
||||
if (isClientMissingInformation)
|
||||
dialog.getLegitimationsInfo().setUserId(LegitimationInfo.CUSTOMER_ANONYM);
|
||||
|
||||
boolean isPin = dialog
|
||||
.getLegitimationsInfo()
|
||||
.getSecurityMethod()
|
||||
.isPIN();
|
||||
|
||||
if (containsHKIDN
|
||||
&& !containsHKTAN
|
||||
&& !dialog.getLegitimationsInfo().isAnonymousAccount()
|
||||
&& !isClientMissingInformation
|
||||
&& isPin
|
||||
&& !dialog.getLegitimationsInfo().isStrongAuthenticated()
|
||||
&& !dialog.getLegitimationsInfo().getSicherheitsfunktion().equals("999")
|
||||
) {
|
||||
LOG.error("Deprecated version or missing HKTAN");
|
||||
throw new DeprecatedVersionHKTAN();
|
||||
}
|
||||
|
||||
if (hnshk != null && hnsha == null) {
|
||||
throw new HBCIValidationException("Signaturabschluss fehlt.");
|
||||
}
|
||||
|
||||
//bei anonymend dialog wird nicht signiert, deshalb wird hier geprüft
|
||||
//ob die Signatur verifiziert werden muss
|
||||
if (hnshk != null) {
|
||||
ReturnDataObject validSignature = new ReturnDataObject(false, "");
|
||||
try {
|
||||
validSignature = validateSignature(hnshk, hnsha, signedSegments);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
//ignored ISO-8859-1 is supported
|
||||
} catch (ElementParseException e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
|
||||
if (!validSignature.isSuccess()) {
|
||||
switch (SecurityMethod.valueOf(hnshk.getSicherheitsprofil().getSicherheitsverfahren() + "_" + hnshk.getSicherheitsprofil().getSicherheitsverfahrensversion())) {
|
||||
case PIN_1:
|
||||
case PIN_2:
|
||||
|
||||
HIRMS hirms = new HIRMS(new byte[0]);
|
||||
hirms.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMS.class).setSegmentVersion(2).setBezugssegment(hnsha.getSegmentkopf().getSegmentNummer()).build());
|
||||
HBCIValidationException exception;
|
||||
if (validSignature.getMessage().equals("")) {
|
||||
Rueckmeldung rueckmeldung = Rueckmeldung.getRueckmeldung("9910");
|
||||
hirms.addRueckmeldung(rueckmeldung);
|
||||
|
||||
exception = new HBCIValidationException("PIN/TAN ungültig.");
|
||||
} else {
|
||||
Rueckmeldung rueckmeldung = new Rueckmeldung(("9910::" + validSignature.getMessage()).getBytes());
|
||||
hirms.addRueckmeldung(rueckmeldung);
|
||||
exception = new HBCIValidationException(validSignature.getMessage());
|
||||
}
|
||||
exception.setRueckmeldung(hirms);
|
||||
throw exception;
|
||||
case RDH_9:
|
||||
case RDH_10:
|
||||
throw new HBCIValidationException("Verarbeitung nicht möglich.", false);
|
||||
default:
|
||||
throw new HBCIValidationException("Kein unterstützes Sicherheitsverfahren verwendet. Signatur ungültig.");
|
||||
}
|
||||
}
|
||||
if (validSignature.getReturnCode() != null) {
|
||||
HIRMS hirms = new HIRMS(new byte[0]);
|
||||
hirms.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMS.class).setSegmentVersion(2).setBezugssegment(hnsha.getSegmentkopf().getSegmentNummer()).build());
|
||||
Rueckmeldung rueckmeldung = Rueckmeldung.getRueckmeldung(validSignature.getReturnCode());
|
||||
hirms.addRueckmeldung(rueckmeldung);
|
||||
dialog.getCurrentMessage().addReplyElement(hirms);
|
||||
}
|
||||
}
|
||||
LOG.info("Signaturprüfung erfolgreich.");
|
||||
|
||||
dialog.getCurrentMessage().getMessageElements().addAll(elements);
|
||||
|
||||
if (hnshk != null) {
|
||||
dialog.getCurrentMessage().setSecurityMethod(SecurityMethod.valueOf(hnshk.getSicherheitsprofil().getSicherheitsverfahren() + "_" + hnshk.getSicherheitsprofil().getSicherheitsverfahrensversion()));
|
||||
dialog.getCurrentMessage().setUserId(hnshk.getSchluesselname().getBenutzerkennung());
|
||||
dialog.getCurrentMessage().setBankId(hnshk.getSchluesselname().getKreditsinstitutkennung().getKreditinstitutscode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft die Signatur-Segmente einer Nachricht.
|
||||
*
|
||||
* @param hnshk Signaturkopf
|
||||
* @param hnsha Signaturabschluss
|
||||
* @param segments signierte Segmente
|
||||
* @return true falls Signatur übereinstimmt, andernfalls false.
|
||||
*/
|
||||
private ReturnDataObject validateSignature(HNSHK hnshk, HNSHA hnsha, List<byte[]> segments) throws UnsupportedEncodingException, ElementParseException, HBCIValidationException {
|
||||
SignatureHelper signatureHelper = SignatureHelperFactory.getSignatureHelper(SecurityMethod.valueOf(hnshk.getSicherheitsprofil().getSicherheitsverfahren() + "_" + hnshk.getSicherheitsprofil().getSicherheitsverfahrensversion()));
|
||||
int sigLength = 0;
|
||||
for (byte[] segment : segments) {
|
||||
sigLength += segment.length;
|
||||
}
|
||||
byte[] signedData = new byte[sigLength + segments.size()];
|
||||
int offset = 0;
|
||||
for (byte[] segment : segments) {
|
||||
System.arraycopy(segment, 0, signedData, offset, segment.length);
|
||||
offset += segment.length;
|
||||
signedData[offset++] = 0x27;
|
||||
}
|
||||
LOG.debug("Data to check Singature: {}", new String(signedData, "ISO-8859-1"));
|
||||
return signatureHelper.validateSignature(signedData, hnshk, hnsha, dialog);
|
||||
}
|
||||
|
||||
public String getDialogId() {
|
||||
return dialogId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (request != null) {
|
||||
parseAndValidateRequest(taskId, request);
|
||||
}
|
||||
} catch (HBCIParseException | SegmentNotSupportedException e) {
|
||||
HIRMS error = new HIRMS(new byte[0]);
|
||||
error.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMS.class).setSegmentVersion(2).build());
|
||||
Rueckmeldung rueckmeldung = Rueckmeldung.getRueckmeldung("9000");
|
||||
error.addRueckmeldung(rueckmeldung);
|
||||
dialog.getErrorInfo().setErrorOccured(true);
|
||||
dialog.getErrorInfo().setErrorSegment(error);
|
||||
} catch (HBCIValidationException hbciValidationException) {
|
||||
|
||||
if (hbciValidationException.isShowDetails()) {
|
||||
HIRMS error;
|
||||
if (hbciValidationException.getRueckmeldung() == null) {
|
||||
error = new HIRMS(new byte[0]);
|
||||
error.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMS.class).setSegmentVersion(2).setSegmentNumber(0).build());
|
||||
Rueckmeldung rueckmeldung = Rueckmeldung.getRueckmeldung("9999");
|
||||
error.addRueckmeldung(rueckmeldung);
|
||||
rueckmeldung = new Rueckmeldung(new byte[0]);
|
||||
rueckmeldung.setRueckmeldungstext(hbciValidationException.getMessage());
|
||||
rueckmeldung.setRueckmeldungscode("9999");
|
||||
error.addRueckmeldung(rueckmeldung);
|
||||
} else {
|
||||
error = hbciValidationException.getRueckmeldung();
|
||||
}
|
||||
dialog.getErrorInfo().setErrorSegment(error);
|
||||
}
|
||||
dialog.getErrorInfo().setErrorOccured(true);
|
||||
} catch (DeprecatedVersionHKTAN e) {
|
||||
HIRMS error;
|
||||
error = new HIRMS(new byte[0]);
|
||||
error.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMS.class).setSegmentVersion(2).setSegmentNumber(0).setBezugssegment(2).build());
|
||||
Rueckmeldung rueckmeldung = Rueckmeldung.getRueckmeldung("9075");
|
||||
error.addRueckmeldung(rueckmeldung);
|
||||
dialog.getErrorInfo().setErrorOccured(true);
|
||||
dialog.getErrorInfo().setErrorSegment(error);
|
||||
} catch (UnregisteredClientProduct e) {
|
||||
HIRMS error = new HIRMS(new byte[0]);
|
||||
error.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMS.class).setSegmentVersion(2).setSegmentNumber(0).setBezugssegment(2).build());
|
||||
Rueckmeldung rueckmeldung = Rueckmeldung.getRueckmeldung("9078");
|
||||
error.addRueckmeldung(rueckmeldung);
|
||||
dialog.getErrorInfo().setErrorOccured(true);
|
||||
dialog.getErrorInfo().setErrorSegment(error);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Unbekannte Exception: {}", e.getMessage());
|
||||
}
|
||||
FinTS3Controller.getInstance().finishedParsing(taskId, dialog);
|
||||
}
|
||||
|
||||
public Dialog getDialog() {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public void setDialog(Dialog dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3;
|
||||
|
||||
import net.petafuel.fuelifints.FinTSServer;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.protocol.IFinTSReplyThread;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNHBK;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.HNHBS;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.Segment;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Bezugsnachricht;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class FinTS3ReplyThread implements IFinTSReplyThread {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(FinTS3ReplyThread.class);
|
||||
|
||||
private Dialog dialog;
|
||||
private FinTSServer finTSServer;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.trace("Respond element count: {}", dialog.getCurrentMessage().getMessageElements().size());
|
||||
|
||||
HNHBK hnhbk = new HNHBK(new byte[0]);
|
||||
HNHBS hnhbs = new HNHBS(new byte[0]);
|
||||
Segmentkopf segmentkopf;// = new Segmentkopf("HNHBK:1:3".getBytes());
|
||||
segmentkopf = Segmentkopf.Builder.newInstance().setSegmentKennung(HNHBK.class).setSegmentNumber(1).setSegmentVersion(3).build();
|
||||
hnhbk.setSegmentkopf(segmentkopf);
|
||||
|
||||
if (dialog.getMessageNumber() == 1 && dialog.getDialogId().isEmpty()) {
|
||||
String dialogId = generateDialogId();
|
||||
dialog.setDialogId(dialogId);
|
||||
}
|
||||
hnhbk.setDialog_id(dialog.getDialogId());
|
||||
hnhbk.setHbci_version(300);
|
||||
hnhbk.setNachrichtennummer(dialog.getMessageNumber());
|
||||
hnhbk.setNachrichtengroesse("012345678901");
|
||||
hnhbk.setBezugsnachricht(new Bezugsnachricht((dialog.getDialogId() + ":" + dialog.getMessageNumber()).getBytes()));
|
||||
|
||||
//segmentkopf = new Segmentkopf(("HNHBS:"+(dialog.getCurrentMessage().getSegmentCount()+1)+":1").getBytes());
|
||||
segmentkopf = Segmentkopf.Builder.newInstance().setSegmentKennung(HNHBS.class).setSegmentNumber(dialog.getCurrentMessage().getSegmentCount() + 1).setSegmentVersion(1).build();
|
||||
hnhbs.setSegmentkopf(segmentkopf);
|
||||
hnhbs.setNachrichtennummer(dialog.getMessageNumber());
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
|
||||
try {
|
||||
byteArrayOutputStream.write(hnhbk.getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
} catch (IOException e) {
|
||||
LOG.error("IOException", e);
|
||||
}
|
||||
for (IMessageElement iMessageElement : dialog.getCurrentMessage().getMessageElements()) {
|
||||
if (iMessageElement != null) {
|
||||
try {
|
||||
byteArrayOutputStream.write(((Segment) iMessageElement).getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException e) {
|
||||
LOG.error("IOException", e);
|
||||
}
|
||||
} else {
|
||||
LOG.error("iMessageElement is null");
|
||||
}
|
||||
}
|
||||
try {
|
||||
byteArrayOutputStream.write(hnhbs.getHbciEncoded());
|
||||
byteArrayOutputStream.write('\'');
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException e) {
|
||||
LOG.error("IOException", e);
|
||||
}
|
||||
byte[] respondBytes = byteArrayOutputStream.toByteArray();
|
||||
int length = respondBytes.length;
|
||||
byte[] lengthBytes = String.format("%012d", length).getBytes();
|
||||
System.arraycopy(lengthBytes, 0, respondBytes, 10, 12);
|
||||
LOG.trace("response length: {}", length);
|
||||
//try {
|
||||
LOG.debug("Response: {}", new String(respondBytes));
|
||||
//} catch (UnsupportedEncodingException e) {
|
||||
//}
|
||||
finTSServer.respond(dialog.getTaskId(), respondBytes, dialog.isLastMessage());
|
||||
}
|
||||
|
||||
private String generateDialogId() {
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
|
||||
SecureRandom random = new SecureRandom();
|
||||
byte[] bytes = messageDigest.digest(new BigInteger(130, random).toString(32).getBytes());
|
||||
LOG.trace("Generated DialogId: {} length: {}", new String(Base64.encode(bytes)), (new String(Base64.encode(bytes))).length());
|
||||
return (new String(Base64.encode(bytes))).replace('+', '-');
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
}
|
||||
return "fallbackMessage#";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDialog(Dialog dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFinTSServer(FinTSServer finTSServer) {
|
||||
this.finTSServer = finTSServer;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* ApplicantAccount sollte in IExecutableElements bei der Kontoverbindung des Auftraggebers gesetzt werden.
|
||||
* Anhand dieser Annotation wird geprüft, ob die Ausführung des entsprechenden Segments für die entsprechende
|
||||
* Kontoverbindung erlaubt ist.
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ApplicantAccount {
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Dependency {
|
||||
Class<?> dependency();
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.annotations;
|
||||
|
||||
public @interface Inject {
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Requires {
|
||||
enum Requirement {
|
||||
EXECUTION_ALLOWED,
|
||||
KUNDENSYSTEM_ID,
|
||||
USER_IDENTIFIED,
|
||||
TAN
|
||||
}
|
||||
|
||||
Requirement[] value();
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.model;
|
||||
|
||||
public enum SecurityMethod {
|
||||
|
||||
PIN_1(1, 10, 16, 2, 6, 13, 2),
|
||||
PIN_2(2, 10, 16, 2, 6, 13, 2),
|
||||
RDH_9(9, 10, 19, 6, 6, 13, 18),
|
||||
RDH_10(10, 10, 19, 6, 6, 13, 2),
|
||||
RAH_9(9, 10, 19, 6, 6, 14, 18),
|
||||
RAH_10(10, 10, 19, 6, 6, 14, 2);
|
||||
|
||||
private final int number;
|
||||
|
||||
private int signaturAlgorithmus;
|
||||
private int operationsModusSignatur;
|
||||
private int verwendungSignaturAlgorithmus;
|
||||
private int hashAlgorithmus;
|
||||
private int verschluesselungsAlgorithmus;
|
||||
private int operationsModusVerschluesselung;
|
||||
|
||||
private SecurityMethod(int number, int signaturAlgorithmus, int operationsModusSignatur, int verwendungSignaturAlgorithmus, int hashAlgorithmus, int verschluesselungsAlgorithmus, int operationsModusVerschluesselung) {
|
||||
this.number = number;
|
||||
this.signaturAlgorithmus = signaturAlgorithmus;
|
||||
this.operationsModusSignatur = operationsModusSignatur;
|
||||
this.verwendungSignaturAlgorithmus = verwendungSignaturAlgorithmus;
|
||||
this.hashAlgorithmus = hashAlgorithmus;
|
||||
this.verschluesselungsAlgorithmus = verschluesselungsAlgorithmus;
|
||||
this.operationsModusVerschluesselung = operationsModusVerschluesselung;
|
||||
}
|
||||
|
||||
public byte[] getHbciDEG() {
|
||||
String asString = this.toString();
|
||||
return asString.replace('_', ':').getBytes();
|
||||
}
|
||||
|
||||
|
||||
public int getVersionNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public int getSignaturAlgorithmus() {
|
||||
return signaturAlgorithmus;
|
||||
}
|
||||
|
||||
public int getOperationsModusSignatur() {
|
||||
return operationsModusSignatur;
|
||||
}
|
||||
|
||||
public int getVerwendungSignaturAlgorithmus() {
|
||||
return verwendungSignaturAlgorithmus;
|
||||
}
|
||||
|
||||
public int getHashAlgorithmus() {
|
||||
return hashAlgorithmus;
|
||||
}
|
||||
|
||||
public int getVerschluesselungsAlgorithmus() {
|
||||
return verschluesselungsAlgorithmus;
|
||||
}
|
||||
|
||||
public int getOperationsModusVerschluesselung() {
|
||||
return operationsModusVerschluesselung;
|
||||
}
|
||||
|
||||
public boolean isPIN() {
|
||||
return this.number == PIN_1.number || this.number == PIN_2.number;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.DatenElementGruppe;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.bin;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.num;
|
||||
import net.petafuel.fuelifints.support.FieldComparator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractElement implements IMessageElement {
|
||||
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AbstractElement.class);
|
||||
|
||||
private boolean stopSkippingUnusedElements = false;
|
||||
|
||||
public void setStopSkippingUnusedElements() {
|
||||
stopSkippingUnusedElements = true;
|
||||
}
|
||||
|
||||
public static String generateEscapedVersion(String s) {
|
||||
String escapedString = "";
|
||||
if (s != null) {
|
||||
for (char c : s.toCharArray()) {
|
||||
switch (c) {
|
||||
case ':':
|
||||
case '+':
|
||||
case '@':
|
||||
case '?':
|
||||
case '\'':
|
||||
escapedString += '?';
|
||||
}
|
||||
escapedString += c;
|
||||
}
|
||||
}
|
||||
return escapedString;
|
||||
}
|
||||
|
||||
public static ElementDescription getMatchingElementDescription(Field f, int segmentVersion) {
|
||||
Element element;
|
||||
if ((element = f.getAnnotation(Element.class)) != null) {
|
||||
for (ElementDescription description : element.description()) {
|
||||
if (description.segmentVersion() == segmentVersion ||
|
||||
description.segmentVersion() == 0)
|
||||
return description;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] getHbciEncoded() {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
List<Field> degs = new LinkedList<Field>();
|
||||
|
||||
int segmentVersion = -1;
|
||||
if (this instanceof Segment) {
|
||||
Segmentkopf segmentkopf = ((Segment) this).getSegmentkopf();
|
||||
if (segmentkopf != null) {
|
||||
segmentVersion = segmentkopf.getSegmentVersion();
|
||||
}
|
||||
}
|
||||
|
||||
Field[] declaredFields = getClass().getDeclaredFields();
|
||||
|
||||
for (Field f : declaredFields) {
|
||||
f.setAccessible(true);
|
||||
if (getMatchingElementDescription(f, segmentVersion) != null)
|
||||
degs.add(f);
|
||||
}
|
||||
Collections.sort(degs, new FieldComparator(segmentVersion));
|
||||
try {
|
||||
removeUnusedDE(degs, segmentVersion);
|
||||
for (int i = 0; i < degs.size(); i++) {
|
||||
Field f = degs.get(i);
|
||||
if (f.getAnnotation(bin.class) != null) {
|
||||
Object value = f.get(this);
|
||||
if (value == null && getMatchingElementDescription(f, segmentVersion).status() == ElementDescription.StatusCode.M) {
|
||||
throw new RuntimeException("Muss Feld nicht gesetzt: " + f.getName() + " typ: " + f.getType().getSimpleName());
|
||||
}
|
||||
if (value != null)
|
||||
byteArrayOutputStream.write((byte[]) f.get(this));
|
||||
} else if (f.getAnnotation(num.class) != null) {
|
||||
Object value = f.get(this);
|
||||
if (value == null && getMatchingElementDescription(f, segmentVersion).status() == ElementDescription.StatusCode.M) {
|
||||
throw new RuntimeException("Muss Feld von Klasse " + this.getClass().getSimpleName() + " nicht gesetzt: " + f.getName() + " typ: " + f.getType().getSimpleName());
|
||||
}
|
||||
if (value != null) {
|
||||
byteArrayOutputStream.write(Integer.toString((Integer) value).getBytes("ISO-8859-1"));
|
||||
}
|
||||
} else if (AbstractElement.class.isAssignableFrom(f.getType())) {
|
||||
AbstractElement abstractElement = (AbstractElement) f.get(this);
|
||||
if (abstractElement == null) {
|
||||
if (getMatchingElementDescription(f, segmentVersion).status() == ElementDescription.StatusCode.M) {
|
||||
LOG.debug(f.getName());
|
||||
throw new RuntimeException("Muss Feld nicht gesetzt: " + f.getName() + " typ: " + f.getType().getSimpleName());
|
||||
} else if (this instanceof DatenElementGruppe) {
|
||||
//falls noch weitere Felder folgen müssen für optionale DEGs alle felder "leer gesetzt werden" sprich es fehlen noch separator character
|
||||
if (i < degs.size() - 1) {
|
||||
//anzahl elemente - 1 für letzte automatisch gesetzte trennzeichen
|
||||
int count = f.getType().getDeclaredFields().length - 1;
|
||||
for (int j = 0; j < count; j++) {
|
||||
byteArrayOutputStream.write(':');
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
byteArrayOutputStream.write(abstractElement.getHbciEncoded());
|
||||
}
|
||||
} else if (List.class.isAssignableFrom(f.getType())) {
|
||||
List list = (List) f.get(this);
|
||||
|
||||
/* Alle List-Typen die kein AbstractElement sind (DEGs/DEs die öfter vorkommen
|
||||
* müssen einen Typ besitzen der sich als String ohne Fehler darstellen lässt.
|
||||
*/
|
||||
if (list != null) {
|
||||
for (int j = 0; j < list.size(); j++) {
|
||||
Object o = list.get(j);
|
||||
if (AbstractElement.class.isAssignableFrom(o.getClass())) {
|
||||
AbstractElement abstractElement = (AbstractElement) o;
|
||||
byteArrayOutputStream.write(abstractElement.getHbciEncoded());
|
||||
} else {
|
||||
Type type = f.getGenericType();
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
type = parameterizedType.getActualTypeArguments()[0];
|
||||
if (type.equals(String.class)) {
|
||||
byteArrayOutputStream.write(o.toString().getBytes("ISO-8859-1"));
|
||||
} else if (type.equals(byte[].class)) {
|
||||
byteArrayOutputStream.write((byte[]) o);
|
||||
}
|
||||
}
|
||||
if (j < list.size() - 1) {
|
||||
byteArrayOutputStream.write(getSeparatorCharacter());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* es sollten lediglich noch Strings übrig bleiben
|
||||
*/
|
||||
Object value = f.get(this);
|
||||
if (value == null && getMatchingElementDescription(f, segmentVersion).status() == ElementDescription.StatusCode.M) {
|
||||
throw new RuntimeException("Muss Feld nicht gesetzt.: " + f.getName());
|
||||
}
|
||||
if (value != null)
|
||||
byteArrayOutputStream.write(generateEscapedVersion(f.get(this).toString()).getBytes("ISO-8859-1"));
|
||||
}
|
||||
if (i < degs.size() - 1) {
|
||||
byteArrayOutputStream.write(getSeparatorCharacter());
|
||||
}
|
||||
}
|
||||
byteArrayOutputStream.flush();
|
||||
} catch (IOException e) {
|
||||
LOG.error("IOException", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
LOG.error("IllegalAccessException", e);
|
||||
}
|
||||
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
protected abstract char getSeparatorCharacter();
|
||||
|
||||
private void removeUnusedDE(List<Field> degs, int segmentVersion) throws IllegalAccessException {
|
||||
if (stopSkippingUnusedElements) {
|
||||
return;
|
||||
}
|
||||
List<Field> toRemove = new LinkedList<Field>();
|
||||
for (int i = degs.size() - 1; i >= 0; i--) {
|
||||
Field f = degs.get(i);
|
||||
if (getMatchingElementDescription(f, segmentVersion).status() == ElementDescription.StatusCode.C ||
|
||||
getMatchingElementDescription(f, segmentVersion).status() == ElementDescription.StatusCode.O) {
|
||||
if (f.get(this) == null || ((f.get(this) instanceof String) && f.get(this).equals(""))) {
|
||||
toRemove.add(f);
|
||||
} else {
|
||||
/*
|
||||
* falls es mehrere optionale Felder gibt und eines davon gesetzt ist müssen die anderen leer bleiben
|
||||
* also abbrechen
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* falls ein pflichtfeld gefunden wird abbrechen
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
degs.removeAll(toRemove);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KreditkartenUmsatz;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Saldo;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.an;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.dat;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.id;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.num;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Name: Kreditkartenumsätze rückmelden
|
||||
* Typ: Segment
|
||||
* Segmentart: Geschäftsvorfall
|
||||
* Kennung: DIKKU
|
||||
* Bezugssegment: DKKKU
|
||||
* Version: 1
|
||||
* Anzahl: 1
|
||||
*/
|
||||
public class DIKKU extends Segment {
|
||||
|
||||
@Element(description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 2,length = -19)})
|
||||
@an
|
||||
private String kreditkartennummer;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 3,status = ElementDescription.StatusCode.O)})
|
||||
@id
|
||||
private String kreditkartenkontonummer;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 4,status = ElementDescription.StatusCode.O)})
|
||||
@id
|
||||
private String kundennummer;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 5)})
|
||||
private Saldo aktuellerSaldo;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 6,status = ElementDescription.StatusCode.O)})
|
||||
@dat
|
||||
private String datumLetzteAbrechnung;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 7,status = ElementDescription.StatusCode.O)})
|
||||
@dat
|
||||
private String vorraussichtlichesAbrechnungsdatum;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 8,status = ElementDescription.StatusCode.O)})
|
||||
private List<KreditkartenUmsatz> umsaetze;
|
||||
|
||||
public DIKKU(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DIKKU(int segmentVersion, int bezugssegment) {
|
||||
super(new byte[0]);
|
||||
segmentkopf = Segmentkopf.Builder.newInstance().setSegmentKennung(DIKKU.class).setSegmentVersion(segmentVersion).setBezugssegment(bezugssegment).build();
|
||||
}
|
||||
|
||||
public Segmentkopf getSegmentkopf() {
|
||||
return segmentkopf;
|
||||
}
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
|
||||
public String getKreditkartennummer() {
|
||||
return kreditkartennummer;
|
||||
}
|
||||
|
||||
public void setKreditkartennummer(String kreditkartennummer) {
|
||||
this.kreditkartennummer = kreditkartennummer;
|
||||
}
|
||||
|
||||
public String getKreditkartenkontonummer() {
|
||||
return kreditkartenkontonummer;
|
||||
}
|
||||
|
||||
public void setKreditkartenkontonummer(String kreditkartenkontonummer) {
|
||||
this.kreditkartenkontonummer = kreditkartenkontonummer;
|
||||
}
|
||||
|
||||
public String getKundennummer() {
|
||||
return kundennummer;
|
||||
}
|
||||
|
||||
public void setKundennummer(String kundennummer) {
|
||||
this.kundennummer = kundennummer;
|
||||
}
|
||||
|
||||
public Saldo getAktuellerSaldo() {
|
||||
return aktuellerSaldo;
|
||||
}
|
||||
|
||||
public void setAktuellerSaldo(Saldo aktuellerSaldo) {
|
||||
this.aktuellerSaldo = aktuellerSaldo;
|
||||
}
|
||||
|
||||
public String getDatumLetzteAbrechnung() {
|
||||
return datumLetzteAbrechnung;
|
||||
}
|
||||
|
||||
public void setDatumLetzteAbrechnung(String datumLetzteAbrechnung) {
|
||||
this.datumLetzteAbrechnung = datumLetzteAbrechnung;
|
||||
}
|
||||
|
||||
public String getVorraussichtlichesAbrechnungsdatum() {
|
||||
return vorraussichtlichesAbrechnungsdatum;
|
||||
}
|
||||
|
||||
public void setVorraussichtlichesAbrechnungsdatum(String vorraussichtlichesAbrechnungsdatum) {
|
||||
this.vorraussichtlichesAbrechnungsdatum = vorraussichtlichesAbrechnungsdatum;
|
||||
}
|
||||
|
||||
public List<KreditkartenUmsatz> getUmsaetze() {
|
||||
return umsaetze;
|
||||
}
|
||||
|
||||
public void setUmsaetze(List<KreditkartenUmsatz> umsaetze) {
|
||||
this.umsaetze = umsaetze;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacade;
|
||||
import net.petafuel.fuelifints.dataaccess.DataAccessFacadeManager;
|
||||
import net.petafuel.fuelifints.dataaccess.dataobjects.CreditCardRevenueDataObject;
|
||||
import net.petafuel.fuelifints.dataaccess.dataobjects.SaldoDataObject;
|
||||
import net.petafuel.fuelifints.model.Dialog;
|
||||
import net.petafuel.fuelifints.model.IDependentElement;
|
||||
import net.petafuel.fuelifints.model.IExecutableElement;
|
||||
import net.petafuel.fuelifints.model.IMessageElement;
|
||||
import net.petafuel.fuelifints.protocol.fints3.annotations.ApplicantAccount;
|
||||
import net.petafuel.fuelifints.protocol.fints3.annotations.Requires;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Betrag;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.BetragSollHabenKennung;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungNational;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KreditkartenUmsatz;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Rueckmeldung;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Saldo;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Transaktionsbeschreibung;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.an;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.dat;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.id;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.num;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.txt;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Name: Kreditkartenumsätze anfordern
|
||||
* Typ: Segment
|
||||
* Kennung: DKKKU
|
||||
* Bezugssegment: -
|
||||
* Version 1
|
||||
* Sender: Kunde
|
||||
*/
|
||||
@Requires({Requires.Requirement.EXECUTION_ALLOWED,
|
||||
Requires.Requirement.KUNDENSYSTEM_ID,
|
||||
Requires.Requirement.USER_IDENTIFIED,
|
||||
Requires.Requirement.TAN})
|
||||
public class DKKKU extends Segment implements IDependentElement, IExecutableElement {
|
||||
|
||||
@Element(description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 2, status = ElementDescription.StatusCode.C)})
|
||||
@ApplicantAccount
|
||||
private KontoverbindungNational kontoverbindungAuftraggeber;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 3, length = -19)})
|
||||
@an
|
||||
private String kreditkartennummer;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 4, status = ElementDescription.StatusCode.C)})
|
||||
@id
|
||||
private String kreditkartenkontonummer;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 5, status = ElementDescription.StatusCode.C)})
|
||||
@id
|
||||
private String kundennummer;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 6, status = ElementDescription.StatusCode.O)})
|
||||
@dat
|
||||
private String vonDatum;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 7, status = ElementDescription.StatusCode.O)})
|
||||
@dat
|
||||
private String bisDatum;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 8, status = ElementDescription.StatusCode.C, length = -4)})
|
||||
@num
|
||||
private Integer maximaleAnzahlEintraege;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 9, status = ElementDescription.StatusCode.C, length = -35)})
|
||||
@an
|
||||
private String aufsetzpunkt;
|
||||
|
||||
private HIRMS statusElement;
|
||||
private List<IMessageElement> replyElements;
|
||||
|
||||
public DKKKU(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public Segmentkopf getSegmentkopf() {
|
||||
return segmentkopf;
|
||||
}
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
|
||||
public KontoverbindungNational getKontoverbindungAuftraggeber() {
|
||||
return kontoverbindungAuftraggeber;
|
||||
}
|
||||
|
||||
public void setKontoverbindungAuftraggeber(KontoverbindungNational kontoverbindungAuftraggeber) {
|
||||
this.kontoverbindungAuftraggeber = kontoverbindungAuftraggeber;
|
||||
}
|
||||
|
||||
public String getKreditkartennummer() {
|
||||
return kreditkartennummer;
|
||||
}
|
||||
|
||||
public void setKreditkartennummer(String kreditkartennummer) {
|
||||
this.kreditkartennummer = kreditkartennummer;
|
||||
}
|
||||
|
||||
public String getKreditkartenkontonummer() {
|
||||
return kreditkartenkontonummer;
|
||||
}
|
||||
|
||||
public void setKreditkartenkontonummer(String kreditkartenkontonummer) {
|
||||
this.kreditkartenkontonummer = kreditkartenkontonummer;
|
||||
}
|
||||
|
||||
public String getKundennummer() {
|
||||
return kundennummer;
|
||||
}
|
||||
|
||||
public void setKundennummer(String kundennummer) {
|
||||
this.kundennummer = kundennummer;
|
||||
}
|
||||
|
||||
public String getVonDatum() {
|
||||
return vonDatum;
|
||||
}
|
||||
|
||||
public void setVonDatum(String vonDatum) {
|
||||
this.vonDatum = vonDatum;
|
||||
}
|
||||
|
||||
public String getBisDatum() {
|
||||
return bisDatum;
|
||||
}
|
||||
|
||||
public void setBisDatum(String bisDatum) {
|
||||
this.bisDatum = bisDatum;
|
||||
}
|
||||
|
||||
public Integer getMaximaleAnzahlEintraege() {
|
||||
return maximaleAnzahlEintraege;
|
||||
}
|
||||
|
||||
public void setMaximaleAnzahlEintraege(Integer maximaleAnzahlEintraege) {
|
||||
this.maximaleAnzahlEintraege = maximaleAnzahlEintraege;
|
||||
}
|
||||
|
||||
public String getAufsetzpunkt() {
|
||||
return aufsetzpunkt;
|
||||
}
|
||||
|
||||
public void setAufsetzpunkt(String aufsetzpunkt) {
|
||||
this.aufsetzpunkt = aufsetzpunkt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusCode execute(Dialog dialog) {
|
||||
statusElement = new HIRMS(new byte[0]);
|
||||
statusElement.setSegmentkopf(Segmentkopf.Builder.newInstance().setSegmentKennung(HIRMS.class).setSegmentVersion(2).setBezugssegment(segmentkopf.getSegmentNummer()).build());
|
||||
DataAccessFacade dataAccessFacade = DataAccessFacadeManager.getAccessFacade(dialog.getBankId());
|
||||
|
||||
boolean operationAllowed = dataAccessFacade.operationAllowedForAccount(dialog.getLegitimationsInfo(), kreditkartennummer, getClass());
|
||||
|
||||
if (!operationAllowed) {
|
||||
Rueckmeldung rueckmeldung = Rueckmeldung.getRueckmeldung("9380");
|
||||
statusElement.addRueckmeldung(rueckmeldung);
|
||||
return StatusCode.ERROR;
|
||||
}
|
||||
|
||||
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
|
||||
Date von = null;
|
||||
Date bis = null;
|
||||
try {
|
||||
if (vonDatum != null && !vonDatum.isEmpty()) {
|
||||
von = simpleDateFormat.parse(vonDatum);
|
||||
if (bisDatum != null && !bisDatum.isEmpty()) {
|
||||
bis = simpleDateFormat.parse(bisDatum);
|
||||
}
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
//ignored sollten bereits geprüft sein
|
||||
}
|
||||
|
||||
List<CreditCardRevenueDataObject> revenues = dataAccessFacade.getCreditCardRevenueData(kreditkartennummer, von, bis, dialog.getLegitimationsInfo());
|
||||
SaldoDataObject saldoDataObject = dataAccessFacade.getSaldo(kreditkartennummer,dialog.getLegitimationsInfo());
|
||||
if(revenues == null || revenues.isEmpty()) {
|
||||
Rueckmeldung rueckmeldung = Rueckmeldung.getRueckmeldung("3010");
|
||||
statusElement.addRueckmeldung(rueckmeldung);
|
||||
return StatusCode.WARNING;
|
||||
}
|
||||
DIKKU dikku = new DIKKU(segmentkopf.getSegmentVersion(), segmentkopf.getSegmentNummer());
|
||||
|
||||
Betrag betrag = new Betrag(new byte[0]);
|
||||
betrag.setWert(String.format(Locale.GERMAN, "%.2f", Math.abs(saldoDataObject.getGebuchterSaldo())));
|
||||
betrag.setWaehrung(saldoDataObject.getWaehrung());
|
||||
|
||||
Saldo saldo = new Saldo(new byte[0]);
|
||||
saldo.setBetrag(betrag);
|
||||
String sollHabenKennzeichen = "C";
|
||||
if(saldoDataObject.getGebuchterSaldo() < 0) {
|
||||
sollHabenKennzeichen = "D";
|
||||
}
|
||||
saldo.setSollHabenKennzeichen(sollHabenKennzeichen);
|
||||
saldo.setDatum(simpleDateFormat.format(new Date()));
|
||||
|
||||
dikku.setAktuellerSaldo(saldo);
|
||||
if(kontoverbindungAuftraggeber != null) {
|
||||
dikku.setKreditkartenkontonummer(kontoverbindungAuftraggeber.getKontonummer());
|
||||
}
|
||||
dikku.setKundennummer(dialog.getLegitimationsInfo().getCustomerId());
|
||||
dikku.setKreditkartennummer(kreditkartennummer);
|
||||
List<KreditkartenUmsatz> umsaetze = new LinkedList<>();
|
||||
for(CreditCardRevenueDataObject creditCardRevenueDataObject : revenues) {
|
||||
KreditkartenUmsatz kreditkartenUmsatz = new KreditkartenUmsatz(new byte[0]);
|
||||
kreditkartenUmsatz.setGetaetigtVon(creditCardRevenueDataObject.getCreditCardNumber());
|
||||
kreditkartenUmsatz.setBelegDatum(simpleDateFormat.format(creditCardRevenueDataObject.getVoucherDate()));
|
||||
kreditkartenUmsatz.setBuchungsDatum(simpleDateFormat.format(creditCardRevenueDataObject.getBookingDate()));
|
||||
BetragSollHabenKennung buchungsbetrag = new BetragSollHabenKennung(new byte[0]);
|
||||
buchungsbetrag.setWert(String.format(Locale.GERMAN, "%.2f", Math.abs(creditCardRevenueDataObject.getAmount())));
|
||||
buchungsbetrag.setWaehrung(saldoDataObject.getWaehrung());
|
||||
buchungsbetrag.setSollHabenKennung("C");
|
||||
if(creditCardRevenueDataObject.getAmount() < 0) {
|
||||
buchungsbetrag.setSollHabenKennung("D");
|
||||
}
|
||||
kreditkartenUmsatz.setBuchungsBetrag(buchungsbetrag);
|
||||
Transaktionsbeschreibung transaktionsbeschreibung = new Transaktionsbeschreibung(new byte[0]);
|
||||
transaktionsbeschreibung.setTransaktionsbeschreibungsgrundtext(creditCardRevenueDataObject.getPurpose());
|
||||
kreditkartenUmsatz.setTransaktionsbeschreibung(transaktionsbeschreibung);
|
||||
kreditkartenUmsatz.setUmsatzAbgerechnet(creditCardRevenueDataObject.isBilled() ? "J" : "N");
|
||||
umsaetze.add(kreditkartenUmsatz);
|
||||
}
|
||||
|
||||
dikku.setUmsaetze(umsaetze);
|
||||
replyElements = new LinkedList<>();
|
||||
replyElements.add(dikku);
|
||||
statusElement.addRueckmeldung(Rueckmeldung.getRueckmeldung("0020"));
|
||||
return StatusCode.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IMessageElement> getReplyMessageElements() {
|
||||
return replyElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMessageElement getStatusElement() {
|
||||
return statusElement;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Element {
|
||||
|
||||
ElementDescription[] description();
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface ElementDescription {
|
||||
|
||||
enum StatusCode {M, O, C}
|
||||
|
||||
int number();
|
||||
|
||||
StatusCode status() default StatusCode.M;
|
||||
|
||||
int length() default 0;
|
||||
|
||||
int segmentVersion() default 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.GebuchteCamtUmsaetze;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungInternational;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.an;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.bin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Name: Kontoumsätze rückmelden/Zeitraum camt
|
||||
* Typ: Segment
|
||||
* Segmentart: Geschäftsvorfall
|
||||
* Kennung: HICAZ
|
||||
* Bezugssegment: HKCAZ
|
||||
* Version: 1
|
||||
* Anzahl: n
|
||||
* Sender: Kreditinstitut
|
||||
*/
|
||||
public class HICAZ extends Segment {
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
|
||||
@Element(description = {@ElementDescription(number = 2)})
|
||||
private KontoverbindungInternational kontoverbindungInternational;
|
||||
|
||||
@Element(description = @ElementDescription(number = 3, length = -256))
|
||||
@an
|
||||
private String camtDescriptor;
|
||||
|
||||
@Element(description = @ElementDescription(number = 4))
|
||||
private GebuchteCamtUmsaetze gebuchteCamtUmsaetze;
|
||||
|
||||
@Element(description = @ElementDescription(number = 5, status = ElementDescription.StatusCode.O))
|
||||
@bin
|
||||
private byte[] nichtGebuchteCamtUmsaetze;
|
||||
|
||||
|
||||
public HICAZ(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public HICAZ(String camtDescriptor, List<byte[]> gebuchteUmsaetze, byte[] nichtGebuchteUmsaetze, Integer segmentNummer, Integer segmentVersion) {
|
||||
super(new byte[0]);
|
||||
segmentkopf = Segmentkopf.Builder.newInstance().setSegmentKennung(getClass()).setSegmentVersion(segmentVersion).setBezugssegment(segmentNummer).build();
|
||||
this.camtDescriptor = camtDescriptor;
|
||||
if (gebuchteUmsaetze != null && gebuchteUmsaetze.size() > 0) {
|
||||
gebuchteCamtUmsaetze = new GebuchteCamtUmsaetze(new byte[0]);
|
||||
for (byte[] b : gebuchteUmsaetze) {
|
||||
gebuchteCamtUmsaetze.addCamtUmsatz(SegmentUtil.wrapBinary(b));
|
||||
}
|
||||
}
|
||||
nichtGebuchteCamtUmsaetze = SegmentUtil.wrapBinary(nichtGebuchteUmsaetze);
|
||||
}
|
||||
|
||||
public Segmentkopf getSegmentkopf() {
|
||||
return segmentkopf;
|
||||
}
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
|
||||
public KontoverbindungInternational getKontoverbindungInternational() {
|
||||
return kontoverbindungInternational;
|
||||
}
|
||||
|
||||
public void setKontoverbindungInternational(KontoverbindungInternational kontoverbindungInternational) {
|
||||
this.kontoverbindungInternational = kontoverbindungInternational;
|
||||
}
|
||||
|
||||
public String getCamtDescriptor() {
|
||||
return camtDescriptor;
|
||||
}
|
||||
|
||||
public void setCamtDescriptor(String camtDescriptor) {
|
||||
this.camtDescriptor = camtDescriptor;
|
||||
}
|
||||
|
||||
public GebuchteCamtUmsaetze getGebuchteCamtUmsaetze() {
|
||||
return gebuchteCamtUmsaetze;
|
||||
}
|
||||
|
||||
public void setGebuchteCamtUmsaetze(GebuchteCamtUmsaetze gebuchteCamtUmsaetze) {
|
||||
this.gebuchteCamtUmsaetze = gebuchteCamtUmsaetze;
|
||||
}
|
||||
|
||||
public byte[] getNichtGebuchteCamtUmsaetze() {
|
||||
return nichtGebuchteCamtUmsaetze;
|
||||
}
|
||||
|
||||
public void setNichtGebuchteCamtUmsaetze(byte[] nichtGebuchteCamtUmsaetze) {
|
||||
this.nichtGebuchteCamtUmsaetze = nichtGebuchteCamtUmsaetze;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.annotations.ApplicantAccount;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Betrag;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungInternational;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.dat;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.num;
|
||||
|
||||
public class HICMB extends Segment{
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 2)})
|
||||
private String auftragsidentifikation;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 3)})
|
||||
@ApplicantAccount
|
||||
private KontoverbindungInternational kontoverbindungInternational;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 4)})
|
||||
@dat
|
||||
private String einreichungsdatum;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 5)})
|
||||
@dat
|
||||
private String ausfuehrungsdatum;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 6)})
|
||||
@num
|
||||
private int anzahlAuftraege;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 7)})
|
||||
private Betrag summeDerBetrage;
|
||||
|
||||
public HICMB(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
|
||||
public void setKontoverbindungInternational(KontoverbindungInternational kontoverbindungInternational) {
|
||||
this.kontoverbindungInternational = kontoverbindungInternational;
|
||||
}
|
||||
|
||||
public void setEinreichungsdatum(String einreichungsdatum) {
|
||||
this.einreichungsdatum = einreichungsdatum;
|
||||
}
|
||||
|
||||
public void setAusfuehrungsdatum(String ausfuehrungsdatum) {
|
||||
this.ausfuehrungsdatum = ausfuehrungsdatum;
|
||||
}
|
||||
|
||||
public void setAnzahlAuftraege(int anzahlAuftraege) {
|
||||
this.anzahlAuftraege = anzahlAuftraege;
|
||||
}
|
||||
|
||||
public void setSummeDerBetrage(Betrag summeDerBetrage) {
|
||||
this.summeDerBetrage = summeDerBetrage;
|
||||
}
|
||||
|
||||
public void setAuftragsidentifikation(String auftragsidentifikation) {
|
||||
this.auftragsidentifikation = auftragsidentifikation;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
|
||||
public class HICME extends Segment {
|
||||
@Element(description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
@Element(description = {@ElementDescription(number = 2,status = ElementDescription.StatusCode.O)})
|
||||
private String auftragsidentifikation;
|
||||
|
||||
public HICME(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public void setAuftragsidentifikation(String auftragsidentifikation) {
|
||||
this.auftragsidentifikation = auftragsidentifikation;
|
||||
}
|
||||
|
||||
public Segmentkopf getSegmentkopf() {
|
||||
return segmentkopf;
|
||||
}
|
||||
|
||||
public String getAuftragsidentifikation() {
|
||||
return auftragsidentifikation;
|
||||
}
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.annotations.ApplicantAccount;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungInternational;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.an;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.bin;
|
||||
|
||||
public class HICSB extends Segment {
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 2)})
|
||||
@ApplicantAccount
|
||||
private KontoverbindungInternational kontoverbindungInternational;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 3)})
|
||||
@an
|
||||
private String sepaDescriptor;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 4)})
|
||||
@bin
|
||||
private byte[] sepaPainMessage;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 5, length = -99, status = ElementDescription.StatusCode.C)})
|
||||
private String auftragsIdentifikation;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 6, status = ElementDescription.StatusCode.O)})
|
||||
private String loeschbar;
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 7, status = ElementDescription.StatusCode.O)})
|
||||
private String aenderbar;
|
||||
|
||||
public HICSB(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public Segmentkopf getSegmentkopf() {
|
||||
return segmentkopf;
|
||||
}
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
|
||||
public KontoverbindungInternational getKontoverbindungInternational() {
|
||||
return kontoverbindungInternational;
|
||||
}
|
||||
|
||||
public void setKontoverbindungInternational(KontoverbindungInternational kontoverbindungInternational) {
|
||||
this.kontoverbindungInternational = kontoverbindungInternational;
|
||||
}
|
||||
|
||||
public String getSepaDescriptor() {
|
||||
return sepaDescriptor;
|
||||
}
|
||||
|
||||
public void setSepaDescriptor(String sepaDescriptor) {
|
||||
this.sepaDescriptor = sepaDescriptor;
|
||||
}
|
||||
|
||||
public byte[] getSepaPainMessage() {
|
||||
return sepaPainMessage;
|
||||
}
|
||||
|
||||
public void setSepaPainMessage(byte[] sepaPainMessage) {
|
||||
this.sepaPainMessage = sepaPainMessage;
|
||||
}
|
||||
|
||||
public String getAuftragsIdentifikation() {
|
||||
return auftragsIdentifikation;
|
||||
}
|
||||
|
||||
public void setAuftragsIdentifikation(String auftragsIdentifikation) {
|
||||
this.auftragsIdentifikation = auftragsIdentifikation;
|
||||
}
|
||||
|
||||
public String getLoeschbar() {
|
||||
return loeschbar;
|
||||
}
|
||||
|
||||
public void setLoeschbar(String loeschbar) {
|
||||
this.loeschbar = loeschbar;
|
||||
}
|
||||
|
||||
public String getAenderbar() {
|
||||
return aenderbar;
|
||||
}
|
||||
|
||||
public void setAenderbar(String aenderbar) {
|
||||
this.aenderbar = aenderbar;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
|
||||
public class HICSE extends Segment {
|
||||
@Element(description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
@Element(description = {@ElementDescription(number = 2,status = ElementDescription.StatusCode.O)})
|
||||
private String auftragsidentifikation;
|
||||
public HICSE(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public Segmentkopf getSegmentkopf() {
|
||||
return segmentkopf;
|
||||
}
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
|
||||
public String getAuftragsidentifikation() {
|
||||
return auftragsidentifikation;
|
||||
}
|
||||
|
||||
public void setAuftragsidentifikation(String auftragsidentifikation) {
|
||||
this.auftragsidentifikation = auftragsidentifikation;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.AngabenEmpfaengerkonten;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.KontoverbindungInternational;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Name: Empfängerkontenbestand rückmelden
|
||||
* Kennung: HICUB
|
||||
* Version: 1
|
||||
* Sender: Kreditinstitut
|
||||
*/
|
||||
public class HICUB extends Segment {
|
||||
|
||||
@Element(description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
@Element(description = {@ElementDescription(number = 2)})
|
||||
private KontoverbindungInternational kontoverbindungInternational;
|
||||
@Element(description = {@ElementDescription(number = 3)})
|
||||
private List<AngabenEmpfaengerkonten> angabenEmpfaengerkonten;
|
||||
|
||||
public HICUB(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public Segmentkopf getSegmentkopf() {
|
||||
return segmentkopf;
|
||||
}
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
|
||||
public KontoverbindungInternational getKontoverbindungInternational() {
|
||||
return kontoverbindungInternational;
|
||||
}
|
||||
|
||||
public void setKontoverbindungInternational(KontoverbindungInternational kontoverbindungInternational) {
|
||||
this.kontoverbindungInternational = kontoverbindungInternational;
|
||||
}
|
||||
|
||||
public List<AngabenEmpfaengerkonten> getAngabenEmpfaengerkonten() {
|
||||
return angabenEmpfaengerkonten;
|
||||
}
|
||||
|
||||
public void setAngabenEmpfaengerkonten(List<AngabenEmpfaengerkonten> angabenEmpfaengerkonten) {
|
||||
this.angabenEmpfaengerkonten = angabenEmpfaengerkonten;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package net.petafuel.fuelifints.protocol.fints3.segments;
|
||||
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.OeffentlicherSchluessel;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Schluesselname;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Segmentkopf;
|
||||
import net.petafuel.fuelifints.protocol.fints3.segments.deg.Zertifikat;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.code;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.id;
|
||||
import net.petafuel.fuelifints.protocol.fints3.validator.validators.num;
|
||||
|
||||
/**
|
||||
* Name: Übermittlung eines öffentlichen Schlüssels
|
||||
* Typ: Segment
|
||||
* Sender: Kreditinstitut
|
||||
*/
|
||||
public class HIISA extends Segment {
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 1)})
|
||||
private Segmentkopf segmentkopf;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 2, length = 1)})
|
||||
@code(restrictions = {"1"})
|
||||
private String nachrichtenbeziehungKodiert;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 3, length = 0)})
|
||||
@id
|
||||
private String austauschkontrollereferenz;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 4, length = -4)})
|
||||
@num
|
||||
private Integer nachrichtenreferenznummer;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 5, length = -3)})
|
||||
@code(restrictions = {"224"})
|
||||
private String bezeichnerFunktionstyp;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 6)})
|
||||
private Schluesselname schluesselname;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 7)})
|
||||
private OeffentlicherSchluessel oeffentlicherSchluessel;
|
||||
|
||||
@Element(
|
||||
description = {@ElementDescription(number = 8, status = ElementDescription.StatusCode.O)})
|
||||
private Zertifikat zertifikat;
|
||||
|
||||
public HIISA(byte[] message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public void setSegmentkopf(Segmentkopf segmentkopf) {
|
||||
this.segmentkopf = segmentkopf;
|
||||
}
|
||||
|
||||
public void setNachrichtenbeziehungKodiert(String nachrichtenbeziehungKodiert) {
|
||||
this.nachrichtenbeziehungKodiert = nachrichtenbeziehungKodiert;
|
||||
}
|
||||
|
||||
public void setAustauschkontrollereferenz(String austauschkontrollereferenz) {
|
||||
this.austauschkontrollereferenz = austauschkontrollereferenz;
|
||||
}
|
||||
|
||||
public void setNachrichtenreferenznummer(Integer nachrichtenreferenznummer) {
|
||||
this.nachrichtenreferenznummer = nachrichtenreferenznummer;
|
||||
}
|
||||
|
||||
public void setBezeichnerFunktionstyp(String bezeichnerFunktionstyp) {
|
||||
this.bezeichnerFunktionstyp = bezeichnerFunktionstyp;
|
||||
}
|
||||
|
||||
public void setSchluesselname(Schluesselname schluesselname) {
|
||||
this.schluesselname = schluesselname;
|
||||
}
|
||||
|
||||
public void setOeffentlicherSchluessel(OeffentlicherSchluessel oeffentlicherSchluessel) {
|
||||
this.oeffentlicherSchluessel = oeffentlicherSchluessel;
|
||||
}
|
||||
|
||||
public void setZertifikat(Zertifikat zertifikat) {
|
||||
this.zertifikat = zertifikat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HIISA{" +
|
||||
"segmentkopf=" + segmentkopf +
|
||||
", nachrichtenbeziehungKodiert='" + nachrichtenbeziehungKodiert + '\'' +
|
||||
", austauschkontrollereferenz='" + austauschkontrollereferenz + '\'' +
|
||||
", nachrichtenreferenznummer=" + nachrichtenreferenznummer +
|
||||
", bezeichnerFunktionstyp='" + bezeichnerFunktionstyp + '\'' +
|
||||
", schluesselname=" + schluesselname +
|
||||
", oeffentlicherSchluessel=" + oeffentlicherSchluessel +
|
||||
", zertifikat=" + zertifikat +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue