All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kapott.hbci.manager.ChallengeInfo Maven / Gradle / Ivy

Go to download

HBCI4j - Home Banking Computer Interface for Java - Clone from https://github.com/hbci4j/hbci4java

There is a newer version: 3.5.46
Show newest version
/*  $Id: ChallengeInfo.java,v 1.9 2011/05/30 12:47:56 willuhn Exp $

 This file is part of HBCI4Java
 Copyright (C) 2001-2008  Stefan Palme

 HBCI4Java is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 HBCI4Java is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.kapott.hbci.manager;

import lombok.extern.slf4j.Slf4j;
import org.kapott.hbci.GV.AbstractHBCIJob;
import org.kapott.hbci.datatypes.SyntaxDE;
import org.kapott.hbci.datatypes.factory.SyntaxDEFactory;
import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.exceptions.InvalidUserDataException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Diese Klasse ermittelt die noetigen HKTAN-Challenge-Parameter fuer einen
 * Geschaeftsvorfall
 */
@Slf4j
public class ChallengeInfo {
    /**
     * Das Singleton.
     */
    private static ChallengeInfo singleton = null;
    private Map data; // Die Parameter-Daten aus der XML-Datei.

    /**
     * ct.
     */
    private ChallengeInfo() {
        log.debug("initializing challenge info engine");

        ////////////////////////////////////////////////////////////////////////////
        // XML-Datei lesen
        InputStream dataStream;

        String filename = "challengedata.xml";
        dataStream = ChallengeInfo.class.getClassLoader().getResourceAsStream(filename);
        if (dataStream == null)
            throw new InvalidUserDataException("*** can not load challenge information from " + filename);

        // mit den so gefundenen xml-daten ein xml-dokument bauen
        Document doc;
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setIgnoringComments(true);
            dbf.setValidating(true);

            DocumentBuilder db = dbf.newDocumentBuilder();
            doc = db.parse(dataStream);
            dataStream.close();
        } catch (Exception e) {
            throw new HBCI_Exception("*** can not load challengedata from file " + filename, e);
        }
        //
        ////////////////////////////////////////////////////////////////////////////

        data = new HashMap<>();

        ////////////////////////////////////////////////////////////////////////////
        // Parsen
        NodeList jobs = doc.getElementsByTagName("job");
        int size = jobs.getLength();

        for (int i = 0; i < size; ++i) {
            Element job = (Element) jobs.item(i);
            String code = job.getAttribute("code");
            data.put(code, new Job(job));
        }
        //
        ////////////////////////////////////////////////////////////////////////////

        log.debug("challenge information loaded");
    }

    /**
     * Erzeugt ein neues Challenge-Info-Objekt.
     *
     * @return das Challenge-Info-Objekt.
     */
    public static synchronized ChallengeInfo getInstance() {
        if (singleton == null)
            singleton = new ChallengeInfo();
        return singleton;
    }

    /**
     * Liefert die Challenge-Daten fuer einen Geschaeftsvorfall.
     *
     * @param code die Segmentkennung des Geschaeftsvorfalls.
     * @return die Challenge-Daten.
     */
    public Job getData(String code) {
        return data.get(code);
    }

    /**
     * Uebernimmt die Challenge-Parameter in den HKTAN-Geschaeftsvorfall.
     *
     * @param task                 der Job, zu dem die Challenge-Parameter ermittelt werden sollen.
     * @param hktan                der HKTAN-Geschaeftsvorfall, in dem die Parameter gesetzt werden sollen.
     * @param hbciTwoStepMechanism die BPD-Informationen zum TAN-Verfahren.
     */
    public void applyParams(AbstractHBCIJob task, AbstractHBCIJob hktan, HBCITwoStepMechanism hbciTwoStepMechanism) {
        String code = task.getHBCICode(); // Code des Geschaeftsvorfalls

        // Job-Parameter holen
        Job job = this.getData(code);

        // Den Geschaeftsvorfall kennen wir nicht. Dann brauchen wir
        // auch keine Challenge-Parameter setzen
        if (job == null) {
            log.info("have no challenge data for " + code + ", will not apply challenge params");
            return;
        }

        HHDVersion version = HHDVersion.find(hbciTwoStepMechanism);
        log.debug("using hhd version " + version);

        // Parameter fuer die passende HHD-Version holen
        HhdVersion hhd = job.getVersion(version.getChallengeVersion());

        // Wir haben keine Parameter fuer diese HHD-Version
        if (hhd == null) {
            log.info("have no challenge data for " + code + " in " + version + ", will not apply challenge params");
            return;
        }

        // Schritt 1: Challenge-Klasse uebernehmen
        String klass = hhd.getKlass();
        log.debug("using challenge klass " + klass);
        hktan.setParam("challengeklass", klass);

        // Schritt 2: Challenge-Parameter uebernehmen
        List params = hhd.getParams();
        for (int i = 0; i < params.size(); ++i) {
            int num = i + 1; // Die Job-Parameter beginnen bei 1
            Param param = params.get(i);

            // Checken, ob der Parameter angewendet werden soll.
            if (!param.isComplied(hbciTwoStepMechanism)) {
                log.debug("skipping challenge parameter " + num + " (" + param.path + "), condition " + param.conditionName + "=" + param.conditionValue + " not complied");
                continue;
            }

            // Parameter uebernehmen. Aber nur wenn er auch einen Wert hat.
            // Seit HHD 1.4 duerfen Parameter mittendrin optional sein, sie
            // werden dann freigelassen
            String value = param.getValue(task);
            if (value == null || value.length() == 0) {
                log.debug("challenge parameter " + num + " (" + param.path + ") is empty");
                continue;
            }

            log.debug("adding challenge parameter " + num + " " + param.path + "=" + value);
            hktan.setParam("ChallengeKlassParam" + num, value);
        }
    }

    /**
     * Eine Bean fuer die Parameter-Saetze eines Geschaeftsvorfalles fuer die HHD-Versionen.
     */
    public static class Job {
        /**
         * Die Parameter fuer die jeweilige HHD-Version.
         */
        private Map versions = new HashMap<>();

        /**
         * ct.
         *
         * @param job der XML-Knoten, in dem die Daten stehen.
         */
        private Job(Element job) {
            NodeList specs = job.getElementsByTagName("challengeinfo");
            int size = specs.getLength();

            for (int i = 0; i < size; ++i) {
                Element spec = (Element) specs.item(i);
                String version = spec.getAttribute("spec");

                this.versions.put(version, new HhdVersion(spec));
            }
        }

        /**
         * Liefert die Challenge-Parameter fuer die angegeben HHD-Version.
         *
         * @param version die HHD-Version.
         * @return die Challenge-Parameter fuer die HHD-Version.
         */
        HhdVersion getVersion(String version) {
            return this.versions.get(version);
        }
    }

    /**
     * Eine Bean fuer den Parameter-Satz eines Geschaeftvorfalles innerhalb einer HHD-Version.
     */
    public static class HhdVersion {
        /**
         * Die Challenge-Klasse.
         */
        private String klass;

        /**
         * Liste der Challenge-Parameter.
         */
        private List params = new ArrayList<>();

        /**
         * ct.
         *
         * @param spec der XML-Knoten mit den Daten.
         */
        private HhdVersion(Element spec) {
            this.klass = spec.getElementsByTagName("klass").item(0).getFirstChild().getNodeValue();

            NodeList list = spec.getElementsByTagName("param");
            int size = list.getLength();
            for (int i = 0; i < size; ++i) {
                Element param = (Element) list.item(i);
                this.params.add(new Param(param));
            }
        }

        /**
         * Liefert die Challenge-Klasse.
         *
         * @return die Challenge-Klasse.
         */
        public String getKlass() {
            return this.klass;
        }

        /**
         * Liefert die Challenge-Parameter fuer den Geschaeftsvorfall in dieser HHD-Version.
         *
         * @return die Challenge-Parameter fuer den Geschaeftsvorfall in dieser HHD-Version.
         */
        public List getParams() {
            return this.params;
        }
    }

    /**
     * Eine Bean fuer einen einzelnen Challenge-Parameter.
     */
    public static class Param {
        /**
         * Der Typ des Parameters.
         */
        private String type;

        /**
         * Der Pfad in den Geschaeftsvorfall-Parametern, unter dem der Wert steht.
         */
        private String path;

        /**
         * Optional: Der Name einer Bedingung, die erfuellt sein muss, damit
         * der Parameter verwendet wird. Konkret ist hier der Name eines Property
         * aus secmechInfo gemeint. Also ein BPD-Parameter.
         */
        private String conditionName;

        /**
         * Optional: Der Wert, den der BPD-Parameter haben muss, damit der Challenge-Parameter
         * verwendet wird.
         */
        private String conditionValue;

        /**
         * ct.
         *
         * @param param der XML-Knoten mit den Daten.
         */
        private Param(Element param) {
            Node content = param.getFirstChild();
            this.path = content != null ? content.getNodeValue() : null;
            this.type = param.getAttribute("type");
            this.conditionName = param.getAttribute("condition-name");
            this.conditionValue = param.getAttribute("condition-value");
        }

        /**
         * Liefert true, wenn entweder keine Bedingung angegeben ist oder
         * die Bedingung erfuellt ist und der Parameter verwendet werden kann.
         *
         * @param hbciTwoStepMechanism die BPD-Informationen zum TAN-Verfahren.
         * @return true, wenn der Parameter verwendet werden kann.
         */
        public boolean isComplied(HBCITwoStepMechanism hbciTwoStepMechanism) {
            if (this.conditionName == null || this.conditionName.length() == 0)
                return true;

            // Wir haben eine Bedingung. Mal schauen, ob sie erfuellt ist.
            String value = hbciTwoStepMechanism.getNeedchallengevalue();
            return value != null && value.equals(this.conditionValue);
        }

        /**
         * Liefert den Typ des Parameters.
         *
         * @return der Typ des Parameters.
         */
        public String getType() {
            return this.type;
        }

        /**
         * Liefert den Pfad zum Wert.
         *
         * @return der Pfad zum Wert.
         */
        public String getPath() {
            return this.path;
        }

        /**
         * Liefert den Wert des Parameters.
         *
         * @param job der Geschaeftsvorfall.
         * @return der Wert des Parameters.
         */
        private String getValue(AbstractHBCIJob job) {
            // Leerer Parameter
            if (this.path == null || this.path.length() == 0)
                return null;

            String value = job.getChallengeParam(this.path);

            // Wert im passenden Format zurueckliefern
            return format(value);
        }

        /**
         * Formatiert den Text abhaengig vom Typ.
         * Wenn kein Typ angegeben ist, wird der Wert unformatiert zurueckgegeben.
         *
         * @param value der zu formatierende Wert.
         * @return der formatierte Wert.
         */
        public String format(String value) {
            // Bei leeren Werten lieferen wir generell NULL.
            // Die Parameter werden dann uebersprungen.
            if (value == null || value.trim().length() == 0)
                return null;

            // Wenn kein Typ angegeben ist, gibts auch nichts zu formatieren.
            // Nein, wir duerfen NICHT SyntaxAN verwenden. Denn die Parameter
            // in ChallengeKlassParams#param[1-9] sind ja bereits als Type AN
            // deklariert. Wuerden wir hier SyntaxAN verwenden, wuerden die
            // Werte dann doppelt codiert werden (das zweite Codieren macht ja
            // anschliessend HBCI4Java intern beim Zusammenbauen des Segments).
            // Was zum Beispiel dazu fuehren wuerde, dass ein Sonderzeichen wie
            // "+" oder "?" doppelt escaped werden wuerde.
            if (this.type == null || this.type.trim().length() == 0)
                return value;

            SyntaxDE syntax = SyntaxDEFactory.createSyntaxDE(this.type, this.path, value, 0, 0);
            return syntax.toString(0);

        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy