0%

Beim Einrichten der IAMAccessor-ID für das Identity and Access Management (IAM) von HCL Domino 11 bin ich in der Anleitung beim Punkt ‘Create functional ID for IAM’ auf folgendes Problem gestoßen: Beim Anlegen der ID via ‘Register’ im Domino Administrator erschien die Meldung:

ID upload of the Notes ID Vault failed

Folgende Lösung hat mir in diesem Fall weitergeholfen:

  1. In der Vault-DB (zu finden unter IBM_ID_VAULT<vault-name>.nsf den User IAMAccessor löschen.
  2. Auf der Konsole im Domino Administrator folgenden Befehl absetzen:

    load updall -R IBM_ID_VAULT<vault-name>.nsf

Anschließend konnte ich den User IAMAccessor wie in der Anleitung beschrieben anlegen.

Manche kennen vielleicht noch das Human Genome Project aus den 90ern, das sich zum Ziel gesetzt hatte, mittels Distributed Computing das menschliche Genom zu entschlüsseln (das Ziel wurde 2003 erreicht). Im Jahr 2004 startete das Projekt SETI@Home, das Astrophysikern mittels Analyse der gigantischen Datenmengen, welche Teleskope weltweit liefern, bei der Suche nach außerirdischem Leben helfen soll. In etwa zeitgleich wurde damals von der Berkeley University das Projekt BOINC (Berkeley Open Infrastructure for Network Computing) ins Leben gerufen, das es für normale Anwender möglich machte, mittels Distributed Computing Projekte aus unterschiedlichen Wissenschaftsbereichen durch Spenden von Rechenleistung zu unterstützen.

Wer möchte, kann nun im Kampf gegen Sars-CoV-2 (das Coronavirus, das die Lungenkrankheit Corvid-19 auslöst) helfen, indem er sich von folding@home den Client herunterlädt und installiert. Anschließend muss man nur noch unter ‘I support research fighting’ den Eintrag ‘any disease’ auswählen. Der Client kann so konfiguriert werden, dass er nur dann, wenn der PC nicht verwendet wird, Berechnungen durchführt, so dass man als Benutzer nicht beeinträchtigt wird. Folding@home ist ein Projekt der Stanford University und des Stanford University Medical Center.

foldingAtHome Screenshot

Endlich habe ich Zeit gefunden meinen Blog zu modernisieren. Viel Spaß!

Solr config

Um Duplikate aus den Suchergebnissen zu entfernen, bietet Solr eine De-Duplication Funktion. De-Duplication in Solr basiert auf der Idee pro Eintrag im Index einen Hash-Wert basierend auf definierten Feldwerten zu erzeugen und diesen dann als Indikator für Duplikate zu verwenden. Das kann sehr nützlich sein, wenn Inhalte über unterschiedliche Urls erreichbar sind - aus Solr-Perspektive sind dies dann zunächst unterschiedliche Inhalte.
Die Einrichtung von De-Duplicate ist einfach: Zunächst muss in der schema.xml des verwendeten Solr-Cores ein neues Feld definiert werden, welches später den Hash enthalten soll:

1
<field name="signatureField" type="string" stored="true" indexed="true" multiValued="false" />

In der solrconfig.xml des Solr-Cores definieren wir als nächstes eine updateRequestProcessorChain, der wir als signatureClass Lookup3Signatur übergeben (das ist ein Hash-verfahren, das performanter als MD5 ist und somit die Crawl-Vorgänge aufgrund der kürzeren Berechnungszeit beschleunigt). Die Felder, über die der Hash gebildet werden soll, definieren wir unter fields und der Hash selbst soll dann in das Feld signatureField geschrieben werden:

1
2
3
4
5
6
7
8
9
10
11
<updateRequestProcessorChain name="dedupe"> 
<processor class="solr.processor.SignatureUpdateProcessorFactory">
<bool name="enabled">true</bool>
<str name="signatureField">signatureField</str>
<bool name="overwriteDupes">false</bool>
<str name="fields">content</str>
<str name="signatureClass">solr.processor.Lookup3Signature</str>
</processor>
<processor class="solr.LogUpdateProcessorFactory" />
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>

Die neue updateRequestProcessorChain wird anschließend dem update-requestHandler bekanntgemacht:

1
2
3
4
5
<requestHandler name="/update" class="solr.UpdateRequestHandler" >
<lst name="defaults">
<str name="update.chain">dedupe</str>
</lst>
</requestHandler>

Wenn das nächste mal der Index neu geschrieben oder aktualisiert wird, dann hat jeder neue Eintrag im Index ein neues Feld, welches den Hash beinhaltet, der auf dem Inhalt ‘content’ basiert.
Damit doppelte Einträge aus der Suche verschwinden, muss bei Suchanfragen Gebrauch von der Filterfunktion gemacht werden. Das geht ganz einfach indem an die Url folgender Parameter angefügt wird:

fq={!collapse field=signatureField}

Weitere Informationen finden sich in der Apache Solr Dokumentation.

Wer mit Visual Studio Code arbeitet und etwas aufgepimptes Markdown haben möchte, der sollte sich die Erweiterung ‘Markdown Preview Enhanced with litvis’ ansehen. Neben Charts kann man damit auch Ablaufdiagramme erzeugen und diese mit Hilfe von Themes unterschiedlich darstellen lassen:

markdown beautified

Jenkins bietet seine Dienste neben der Weboberfläche ebenfalls via Rest-Api an. Wer bei Verwendung dieser die Sicherheit erhöhen möchte, kann in den Einstellungen von Jenkins u.a. die CSRF Protection aktivieren um, Cross Site Request Forgery Angriffe zu verhindern. Jenkins akzeptiert nach Aktivierung des Features Rest-Service Aufrufe dann nur, wenn dem Request ein Token im Header beigefügt wird (in der Jenkins Dokumentation wird dies ‘crumb’ genannt). Als quick & dirty Lösung kann man mittels wget, wie in der Dokumentation beschrieben, ein Token generieren. Dieses kann man dann z.B. über Properties in die Anwendung einfließen lassen. Das ist eine schnelle Lösung für erste Tests, hat aber neben sicherheitstechnischen Bedenken den Nachteil, dass das Token an die Session gebunden ist: wird die Anwendung, die die Rest-Aufrufe durchführt in der Testumgebung beispielsweise auf verschiedene Applicationservern parallel getestet und dabei das gleiche Token verwendet, so erhält der zweite Aufrufer einen Status 403 zurück: invalid crumb.

Viel besser ist es vor jedem Rest-Aufruf ein gültiges Token von Jenkins anzufordern - Jenkins bietet hierfür einen eigenen Rest-Service, der wahlweise im json oder xml Format ein Token zurückliefert. Es bietet sich an hierfür eine eigene Funktion zu schreiben, die bei Bedarf den Tokennamen sowie das Token selbst zurückliefert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Before a jenkins rest service can be called, we need to get a crumb from jenkins. This crumb needs to be added to the http-header when calling a rest service.
*
* @return m - a Map containg the name of the crumb and the value of the crumb as Strings.
* @throws Exception
*/
private Map<String, String> getCrumbFromJenkins() throws Exception
{
HashMap<String, String> m = new HashMap<String, String>();

HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + getAuthenticationCode());

HttpEntity<String> request = new HttpEntity<String>(headers);
RestTemplate restTemplate = new RestTemplate();

ResponseEntity<Object> response = restTemplate.exchange("https://dev.meine-domain.de:8090/crumbIssuer/api/json", HttpMethod.GET, request, Object.class);
CrumbJson crumbJson = new Gson().fromJson(response.getBody().toString(), CrumbJson.class);

m.put("name", crumbJson.crumbRequestField);
m.put("value", crumbJson.crumb);

return m;
}

public class CrumbJson {
public String crumb;
public String crumbRequestField;
}

Zur Zeit arbeite ich an einem spannenden Projekt: Ziel ist die Erstellung einer Java basierten Webanwendung, die verschiedene Workflows inkl. LDAP-basiertem Rechtemanagement für Softwarereleases abbildet. Im Kontext dieser Workflows müssen Daten aus unterschiedlichen Quellen (z.B. SVN, Git, Jenkins) abgerufen, aufbereitet, paketiert und in definierten Formaten an bestimmte Ziele (FTP-Server, Network-shares etc.) geschickt werden. U.a. ist als Format hier das ZIP-Format (mit Verschlüsselung) vorgesehen.

Das klingt zunächst sehr simpel, jedoch unterstützt Java in der Version 8 (Projektvorgabe) zwar das Erstellen von zip Files (package: java.util.zip), jedoch keine Verschlüsselung. Ein Blick auf mvnrepository.com liefert hierzu einige Treffer.

Mit am populärsten dürfte sicherlich ‘Apache Commons Compress’ sein, jedoch zeigt ein Blick in die Dokumentation, dass die Verschlüsselung von Zip-files nicht unterstützt wird (wohl aber von anderen Formaten wie 7z, was mir jedoch leider nicht weiter hilft). Gleiches gilt für ‘Snappy Java’, hier lässt sich bereits in der Liste der Features kein Wort zum Thema Verschlüsselung finden. Nach einem kurzen Vergleich der unterschiedlichen Bibliotheken habe ich mich schließlich für Zip4J von Lingala entschieden. Die Verwendung ist simpel, jedoch enthält der Konstruktor der Klasse ZipFile, der einen String als Argument entgegen nimmt, meiner Ansicht nach einen Fehler:

1
2
ZipFile zip = new ZipFile("C:\\test\\test.zip");
zip.addFile(srcFile, params);
1
2
Exception:
net.lingala.zip4j.exception.ZipException: Probably not a zip file or a corrupted zip file

Wie ich im Dateisystem sehen kann, wird zwar eine Datei test.zip erzeugt, diese ist jedoch leer und besitzt eine Größe von 0kb.
Nach einigen Tests habe ich festgestellt, dass der andere Konstruktor, der ein File-Objekt als Argument erwartet, besser funktioniert. Zunächst liefert

1
2
File ziel = new File("C:\\test\\", "test.zip");
ZipFile zip = new ZipFile(ziel.getAbsoluteFile());

jedoch wieder die gleiche Exception. Mangelnde Rechte im Dateisystem seitens der Anwendung habe ich durch einen kurzen Test ausgeschlossen, ein

1
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("C:\\test\\test.zip"))

legt problemlos die gewünschte Zip-Datei (allerdings unverschlüsselt) an und auch ein anschließendes Befüllen des Zips ist möglich. Nach einigen Tests hat sich herausgestellt, dass das Problem mit dem Pfad zu tun hat, denn die Verwendung des temp-Dirs funktioniert hier einwandfrei:

1
2
3
File ziel = new File(System.getProperty("java.io.tmpdir"), "test.zip");
ZipFile zip = new ZipFile(ziel.getAbsoluteFile());
zip.addFile(srcFile, params);

Wie erwähnt, ermöglicht es Zip4J verschlüsselte Zip-Archive zu erstellen. Hierzu muss lediglich ein ZipParameters-Objekt erzeugt und als zweites Argument z.B. an die addFile()-Funktion übergeben werden:

1
2
3
4
5
6
7
ZipParameters params = new ZipParameters();
params.setCompressionLevel(Zip4jConstants.COMP_DEFLATE);
params.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_MAXIMUM);
params.setEncryptFiles(true);
params.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
params.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
params.setPassword("Passw0rt");

Die maximal unterstützte Schlüssellänge im Fall von AES beträgt 256 bit. In Bezug auf das verschlüsselte zip-File ist zu beachten, dass nur die einzelnen im Archiv enthaltenen Dateien verschlüsselt werden, nicht jedoch der Index, d.h. eine Auflistung der Dateinamen ist auch ohne Passworteingabe möglich.

Sofern jemand noch eine bessere Lösung für das Generieren von verschlüsselten Zip-Archiven kennt, würde ich mich über einen entsprechenden Hinweisen in den Kommentaren freuen!

Am 21.03 und 22.03 fand in München das Hello Alexa Bootcamp von Amazon statt. Da wir bereits seit einiger Zeit mit Alexa Skills sowie der Integration von Alexa in verschiedene Produkte experimentieren, waren wir natürlich vor Ort. Die Veranstaltung war gut besucht, sehr interessant und ich habe einige gute neue Ideen für unsere Projekte mitgenommen. Woran wir bei der SIT aktuell unter anderem arbeiten, ist hier nachzulesen.

Ich denke, dass Amazon mit dem Konzept der Erweiterbarkeit von Alexa durch Drittanbieter gegenüber anderen Sprachassistenten einen signifikanten Vorteil hat. Wenn man berücksichtigt, für welche neuen Geräte Alexa bereits angekündigt wurde, dürfte das alles noch sehr spannend werden!