OpenSSL / SSL Hosting in NiFi
Published: 2020-01-22 23:03:59

---
title: OpenSSL / SSL Hosting in NiFi
published: true
date: 2019-09-09 16:22:00 UTC
tags: 
canonical_url: 
---

  
<li-image align="inline" alt="13165-webingest1.png" height="1004" id="13025i7790695B23BCF373" resized="false" size="medium" sourcetype="new" width="1214"></li-image>  
1. Host a Web Page (index.html) via HTTP GET with 200 OK Status  
2. Receive POST from that page via AJAX with browser data  
3. Extract Content and Attributes  
4. Build a JSON file of HTTP data  
5. Store it  
<li-image align="inline" alt="13168-webingestattributes.png" height="464" id="13026i966F537F9880ECDB" resized="false" size="medium" sourcetype="new" width="679"></li-image>  
To accept location in a phone or modern browser you must be running SSL.  
So I added that for this HTTP Request.  
  
Use openssl to create your 2048 RSA X509, PKCS12, JKS Keystore, Import Trust Store and import in browser  
  
  
<li-image align="inline" alt="13167-webingeststandardsslcontext.png" height="379" id="13027iB298BEABB5318844" resized="false" size="medium" sourcetype="new" width="599"></li-image>  
  
Your web page can be any web page, just POST back via AJAX or Form Submit.  
  
<li-image align="inline" alt="13169-webingestwebpage.png" height="612" id="13028iA684F87F2F787EAA" resized="false" size="medium" sourcetype="new" width="454"></li-image>  

```
\<html\>
\<head\>
\<title\>NiFi Browser Data Acquisition\</title\>
\<body\>
\<script\>
// Usage
window.onload = function() {

navigator.getBattery().then(function(battery) {
 console.log(battery.level);
 battery.addEventListener('levelchange', function() {
 console.log(this.level);
 });
});

};

////////////// print these

 var latitude = "";
 var longitude = "";
 var ips = "";
 var batteryInfo = "";
 var screenInfo = screen.width +","+ screen.height + "," +
 screen.availWidth +","+ screen.availHeight + "," +
 screen.colorDepth + "," + screen.pixelDepth;
 var pluginsInfo = "";
 var coresInfo = "";

/////////////

////// Set Plugins
 for (var i = 0; i \< 12; i++) {
 if ( typeof window.navigator.plugins[i] !== 'undefined' ) { 
 pluginsInfo += window.navigator.plugins[i].name + ', '; 
 }
 }
 

////// Set Cores
if ( window.navigator.hardwareConcurrency \> 0 ) {
 coresInfo = window.navigator.hardwareConcurrency + " cores";
}

/////////////
/// send the information to the server
function loadDoc() {
 var xhttp = new XMLHttpRequest();
 xhttp.onreadystatechange = function() {
 if (this.readyState == 4 && this.status == 200) {
 document.getElementById("demo").innerHTML = 'Sent.';
 }
 };
 // /send
 xhttp.open("POST", "/send", true);
 xhttp.setRequestHeader("Content-type", "application/json");
 xhttp.send('{"plugins":"' + pluginsInfo +
 '", "screen":"' + screenInfo + 
 '", "cores":"' + coresInfo + 
 '", "battery":"' + batteryInfo + 
 '", "ip":"' + ips + 
 '", "lat":"' + latitude + '", "lng":"' + longitude + '"}')
}

////////////
function geoFindMe() {
 var output = document.getElementById("out");

 if (!navigator.geolocation){
 output.innerHTML = "\<p\>Geolocation is not supported by your browser\</p\>";
 return;
 }

 function success(position) {
 latitude = position.coords.latitude;
 longitude = position.coords.longitude;

 output.innerHTML = '\<p\>Latitude is ' + latitude + '° \<br\>Longitude is ' + longitude + '°\</p\>';

 var img = new Image();
 img.src="https://maps.googleapis.com/maps/api/staticmap?center=" + latitude + "," + longitude + "&zoom=13&size=300x300&sensor=false";

 output.appendChild(img);
 }

 function error() {
 output.innerHTML = "Unable to retrieve your location";
 }

 output.innerHTML = "\<p\>Locating…\</p\>";

 navigator.geolocation.getCurrentPosition(success, error);
}

//get the IP addresses associated with an account
function getIPs(callback){
 var ip\_dups = {};

 //compatibility for firefox and chrome
 var RTCPeerConnection = window.RTCPeerConnection
 || window.mozRTCPeerConnection
 || window.webkitRTCPeerConnection;
 var useWebKit = !!window.webkitRTCPeerConnection;

 //bypass naive webrtc blocking using an iframe
 if(!RTCPeerConnection){
 //NOTE: you need to have an iframe in the page right above the script tag
 //
 //\<iframe id="iframe" sandbox="allow-same-origin" style="display: none"\>\</iframe\>
 //\<script\>...getIPs called in here...
 //
 var win = iframe.contentWindow;
 RTCPeerConnection = win.RTCPeerConnection
 || win.mozRTCPeerConnection
 || win.webkitRTCPeerConnection;
 useWebKit = !!win.webkitRTCPeerConnection;
 }

 //minimal requirements for data connection
 var mediaConstraints = {
 optional: [{RtpDataChannels: true}]
 };

 var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};

 //construct a new RTCPeerConnection
 var pc = new RTCPeerConnection(servers, mediaConstraints);

 function handleCandidate(candidate){
 //match just the IP address
 var ip\_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
 var ip\_addr = ip\_regex.exec(candidate)[1];

 //remove duplicates
 if(ip\_dups[ip\_addr] === undefined)
 callback(ip\_addr);

 ip\_dups[ip\_addr] = true;
 }

 //listen for candidate events
 pc.onicecandidate = function(ice){

 //skip non-candidate events
 if(ice.candidate)
 handleCandidate(ice.candidate.candidate);
 };

 //create a bogus data channel
 pc.createDataChannel("");

 //create an offer sdp
 pc.createOffer(function(result){

 //trigger the stun server request
 pc.setLocalDescription(result, function(){}, function(){});

 }, function(){});

 //wait for a while to let everything done
 setTimeout(function(){
 //read candidate info from local description
 var lines = pc.localDescription.sdp.split('\n');

 lines.forEach(function(line){
 if(line.indexOf('a=candidate:') === 0)
 handleCandidate(line);
 });
 }, 1000);
}

window.addEventListener("load", function (ev) {
 "use strict";
 var log = document.getElementById("log");
 // [https://dvcs.w3.org/hg/dap/raw-file/tip/sensor-api/Overview.html](https://dvcs.w3.org/hg/dap/raw-file/tip/sensor-api/Overview.html)
 window.addEventListener("devicetemperature", function (ev) {
 log.textContent += "devicetemperature " + ev.value + "\n";
 }, false);
 window.addEventListener("devicepressure", function (ev) {
 log.textContent += "devicepressure " + ev.value + "\n";
 }, false);
 window.addEventListener("devicelight", function (ev) {
 log.textContent += "devicelight " + ev.value + "\n";
 // toy tric
 log.style.color = "rgb(" + (255 - 2\*ev.value) + ",0,0)";
 log.style.backgroundColor = "rgb(0,0," + (2\*ev.value) + ")";
 }, false);
 window.addEventListener("deviceproximity", function (ev) {
 log.textContent += "deviceproximity " + ev.value + "\n";
 // toy tric
 if (ev.value \< 3) navigator.vibrate([300, 100, 100]);
 }, false);
 window.addEventListener("devicenoise", function (ev) {
 log.textContent += "devicenoise " + ev.value + "\n";
 }, false);
 window.addEventListener("devicehumidity", function (ev) {
 log.textContent += "devicehumidity " + ev.value + "\n";
 }, false);

 //https://wiki.mozilla.org/Magnetic\_Field\_Events
 window.addEventListener("devicemagneticfield", function (ev) {
 log.textContent += "devicemagneticfield " + [ev.x, ev.y, ev.x]+ "\n";
 }, false);

 // [https://dvcs.w3.org/hg/dap/raw-file/default/pressure/Overview.html](https://dvcs.w3.org/hg/dap/raw-file/default/pressure/Overview.html)
 window.addEventListener("atmpressure", function (ev) {
 log.textContent += "atmpressure " + ev.value + "\n";
 }, false);

 // [https://dvcs.w3.org/hg/dap/raw-file/tip/humidity/Overview.html](https://dvcs.w3.org/hg/dap/raw-file/tip/humidity/Overview.html)
 window.addEventListener("humidity", function (ev) {
 log.textContent += "humidity " + ev.value + "\n";
 }, false);

 // [https://dvcs.w3.org/hg/dap/raw-file/tip/temperature/Overview.html](https://dvcs.w3.org/hg/dap/raw-file/tip/temperature/Overview.html)
 window.addEventListener("temperature", function (ev) {
 log.textContent += "temperature " + [ev.f, ev.c, ev.k, ev.value] + "\n";
 }, false);

 // [https://dvcs.w3.org/hg/dap/raw-file/tip/battery/Overview.html](https://dvcs.w3.org/hg/dap/raw-file/tip/battery/Overview.html)
 try {
 if (typeof navigator.getBattery === "function") {
 navigator.getBattery().then(function (battery) {
 log.textContent += "battery.level " + battery.level + "\n";
 log.textContent += "battery.charging " + battery.charging + "\n";

 batteryInfo = "battery.level=" + battery.level + "," + 
 "battery.charging=" + battery.charging;

 log.textContent += "battery.chargeTime " + battery.chargeTime + "\n";
 log.textContent += "battery.dischargeTime " + battery.dischargeTime + "\n";
 battery.addEventListener("levelcharge", function (ev) {
 log.textContent += "change battery.level " + battery.level + "\n";
 }, false);
 }).catch(function (err) {
 log.textContent += err.toString() + "\n";
 });
 } else {
 log.textContent += "";
 }
 } catch (ex) {
 log.textContent += ex.toString() + "\n";
 }
}, false);

\</script\>

\<p\>
\<br\>
DEMO: Send Data to HDF / Apache NiFi via HandleHTTPRequest
\<br\>

\<p\>\<button onclick="geoFindMe()"\>Show my location\</button\>\</p\>

\<div id="out"\>\</div\>

\<div id="demo"\>\</div\>

\<pre id="log"\>\</pre\>
 
\<button type="button" onclick="loadDoc()"\>Send data to Apache NiFi SSL Server\</button\>

\<iframe id="iframe" sandbox="allow-same-origin" style="display: none"\>\</iframe\>
\<script\>

getIPs(function(ip){ips = ip;});

\</script\>
\</body\>
\</html\>
```
**index.html** : A web page to grab user information.  
[mobile-ingest-v3.xml](https://community.cloudera.com/legacyfs/online/attachments/13166-mobile-ingest-v3.xml) : Apache NiFi 1.1.x template.  
**Note:** Different browsers, devices, phones, tables and versions will send different values. Users should get a location request pop-up.  
**JSON Result File**  

```
{
 "http.request.uri" : "/send",
 "http.context.identifier" : "a4f9ae25-5f49-463e-97eb-c8a6bf3be8a7",
 "http.remote.host" : "192.168.1.151",
 "http.headers.Host" : "192.168.1.151:9178",
 "http.local.name" : "192.168.1.151",
 "http.headers.DNT" : "1",
 "plugins" : "Widevine Content Decryption Module, Shockwave Flash, Chrome PDF Viewer, Native Client, Chrome PDF Viewer, ",
 "latitude" : "40.2681799",
 "http.headers.Accept" : "\*/\*",
 "battery" : "battery.level=1,battery.charging=true",
 "uuid" : "a2f299ae-6ef6-480d-a359-1362d25abe76",
 "http.request.url" : "https://192.168.1.151:9178/send",
 "http.server.name" : "192.168.1.151",
 "http.character.encoding" : "UTF-8",
 "path" : "./",
 "cores" : "8 cores",
 "http.remote.addr" : "192.168.1.151",
 "http.headers.User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10\_12\_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
 "http.method" : "POST",
 "http.headers.Connection" : "keep-alive",
 "longitude" : "-74.5291745",
 "http.server.port" : "9178",
 "ip" : "192.168.1.151",
 "mime.type" : "application/json",
 "http.locale" : "en\_US",
 "http.headers.Accept-Encoding" : "gzip, deflate, br",
 "http.headers.Origin" : "https://192.168.1.151:9178",
 "http.servlet.path" : "",
 "http.local.addr" : "192.168.1.151",
 "filename" : "1082639525534467",
 "http.headers.Referer" : "https://192.168.1.151:9178/",
 "http.headers.Accept-Language" : "en-US,en;q=0.8",
 "http.headers.Content-Length" : "253",
 "http.headers.Content-Type" : "application/json",
 "RouteOnAttribute.Route" : "isjsonpost"
}
```
**References:**  
  

- [https://github.com/tspannhw/webdataingest](https://github.com/tspannhw/webdataingest)
- [http://webkay.robinlinus.com/](http://webkay.robinlinus.com/)
- [https://github.com/RobinLinus/autofill-phishing](https://github.com/RobinLinus/autofill-phishing)
- [https://github.com/RobinLinus/ubercookie](https://github.com/RobinLinus/ubercookie)
- [https://github.com/RobinLinus/socialmedia-leak](https://github.com/RobinLinus/socialmedia-leak)
- [https://www.w3schools.com/jsref/prop\_screen\_availheight.asp](https://www.w3schools.com/jsref/prop_screen_availheight.asp)
- [https://community.hortonworks.com/articles/27033/https-endpoint-in-nifi-flow.html](https://community.hortonworks.com/articles/27033/https-endpoint-in-nifi-flow.html)
- [http://www.batchiq.com/nifi-configuring-ssl-auth.html](http://www.batchiq.com/nifi-configuring-ssl-auth.html)
- [https://community.hortonworks.com/articles/886/securing-nifi-step-by-step.html](https://community.hortonworks.com/articles/886/securing-nifi-step-by-step.html)
- [http://mobilehtml5.org/](http://mobilehtml5.org/)
- [https://gist.github.com/bellbind/c60d7008e86c34a76aa1](https://gist.github.com/bellbind/c60d7008e86c34a76aa1)
- [https://github.com/coremob/camera](https://github.com/coremob/camera)
- [http://www.girliemac.com/presentation-slides/html5-mobile-approach/deviceAPIs.html?full#23](http://www.girliemac.com/presentation-slides/html5-mobile-approach/deviceAPIs.html?full#23)
- [https://github.com/girliemac/sushi-compass/blob/master/js/app.js](https://github.com/girliemac/sushi-compass/blob/master/js/app.js)
- [https://github.com/noipfraud/IPLock](https://github.com/noipfraud/IPLock)
- [http://www.tomanthony.co.uk/blog/detect-visitor-social-networks/](http://www.tomanthony.co.uk/blog/detect-visitor-social-networks/)
- [https://appsec-labs.com/html5/#toggle-id-5](https://appsec-labs.com/html5/#toggle-id-5)
- [https://mobiforge.com/design-development/sense-and-sensor-bility-access-mobile-device-sensors-with-javascript](https://mobiforge.com/design-development/sense-and-sensor-bility-access-mobile-device-sensors-with-javascript)
- [https://www.html5rocks.com/en/tutorials/device/orientation/](https://www.html5rocks.com/en/tutorials/device/orientation/)
- [http://qnimate.com/html5-proximity-api/](http://qnimate.com/html5-proximity-api/)
  
  
  
  
**Resources**  
  
[https://www.freecodecamp.org/news/openssl-command-cheatsheet-b441be1e8c4a/](https://www.freecodecamp.org/news/openssl-command-cheatsheet-b441be1e8c4a/)  
[https://www.ibm.com/support/knowledgecenter/en/SSMNED\_5.0.0/com.ibm.apic.cmc.doc/task\_apionprem\_gernerate\_self\_signed\_openSSL.html](https://www.ibm.com/support/knowledgecenter/en/SSMNED_5.0.0/com.ibm.apic.cmc.doc/task_apionprem_gernerate_self_signed_openSSL.html)  
[https://blogs.oracle.com/blogbypuneeth/steps-to-create-a-self-signed-certificate-using-openssl](https://blogs.oracle.com/blogbypuneeth/steps-to-create-a-self-signed-certificate-using-openssl)  
[https://www.batchiq.com/nifi-configuring-ssl-auth.html](https://www.batchiq.com/nifi-configuring-ssl-auth.html)  
[http://www.treselle.com/blog/apache-nifi-data-crawling-from-https-websites/](http://www.treselle.com/blog/apache-nifi-data-crawling-from-https-websites/)  
[https://www.tomaszezula.com/2016/11/06/using-ssl-with-nifi/](https://www.tomaszezula.com/2016/11/06/using-ssl-with-nifi/)  
[https://community.cloudera.com/t5/Support-Questions/Nifi-WebSocket-Secure-wss/m-p/237209](https://community.cloudera.com/t5/Support-Questions/Nifi-WebSocket-Secure-wss/m-p/237209)  
[https://nifi.apache.org/docs/nifi-docs/components/org.apache.nifi/nifi-ssl-context-service-nar/1.9.0/org.apache.nifi.ssl.StandardRestrictedSSLContextService/index.html](https://nifi.apache.org/docs/nifi-docs/components/org.apache.nifi/nifi-ssl-context-service-nar/1.9.0/org.apache.nifi.ssl.StandardRestrictedSSLContextService/index.html)  
  
  
<style type="text/css">p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px 'Andale Mono'; color: #2fff12; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)} span.s1 {font-variant-ligatures: no-common-ligatures} </style>  

openssl req -newkey rsa:2048 -x509 -keyout cakey.pem -out cacert.pem -days 3650 

openssl pkcs12 -export -in cacert.pem -inkey cakey.pem -out identity.p12 -name "mykey" 

keytool -importkeystore -destkeystore identity.jks -deststorepass password -srckeystore identity.p12 -srcstoretype PKCS12 -srcstorepass password  

keytool -import -file cacert.pem -keystore trust.jks -storepass password

openssl x509 -in cacert.pem -noout -text

cat cakey.pem cacert.pem \> server.pem    
  
[http://www.gaudreault.ca/nifi-kerberize-ssl/](http://www.gaudreault.ca/nifi-kerberize-ssl/)