Category: Coding

Filtering HTML Drop-down

I’ve got a few drop-downs that I’ve added filtering on the drop-down – start typing and you’ll see the options that match your string. But I needed to mirror an application functionality where you select a category and are then presented with a list of options that fit the category.

Here’s the drop-down selector for the categories

    echo "      <div class=\"row\">\n";
    echo "          <div class=\"col-md-12 col-sm-12 col-lg-12 col-xs-12\">\n";
    echo "              <div class=\"row\">\n";
    echo "                  <div class=\"row\">\n";
    echo "                      <div class=\"col-md-2 col-sm-2 col-lg-2 col-xs-2 text-left\">\n";
    echo "                          <span><strong>Location Category:</strong></span>\n";
    echo "                      </div>\n";
    echo "                      <div class=\"col-md-10 col-sm-10 col-lg-10 col-xs-10 text-left form-group\">\n";
    echo "                          <select name=\"strLocCategory\" id=\"strLocCategory\" readonly/>&nbsp;\n";
    echo "                              <option class=\"NoSelection\" value=\"-----\">-----</option>\n";
    echo "                              <option class=\"Building\" value=\"201\">BUILDING</option>\n";
    echo "                              <option class=\"NonBuilding\" value=\"202\">NONBUILDING</option>\n";
    echo "                              <option class=\"Switching\" value=\"203\">SWITCHING</option>\n";
    echo "                              <option class=\"NonSwitching\" value=\"204\">NONSWITCHING</option>\n";
    echo "                              <option class=\"MiscSwitching\" value=\"205\">MISC SWITCHING</option>\n";
    echo "                              <option class=\"IntlSwitching\" value=\"206\">INTL SWITCHING</option>\n";
    echo "                              <option class=\"Switchboard\" value=\"207\">SWITCHBOARD</option>\n";
    echo "                              <option class=\"Customer\" value=\"208\">CUSTOMER</option>\n";
    echo "                              <option class=\"Room\" value=\"209\">ROOM</option>\n";
    echo "                              <option class=\"Other\" value=\"210\">OTHER</option>\n";
    echo "                          </select>\n";
    echo "                      </div>\n";
    echo "                  </div>\n";

And here’s the drop-down selector I want to filter based on category — there are a lot of options. The class for each option includes the category selectors that will include the option in the drop-down.

    echo "      <div class=\"row\">\n";
    echo "          <div class=\"col-md-12 col-sm-12 col-lg-12 col-xs-12\">\n";
    echo "              <div class=\"row\">\n";
    echo "                  <div class=\"row\">\n";
    echo "                      <div class=\"col-md-2 col-sm-2 col-lg-2 col-xs-2 text-left\">\n";
    echo "                          <span><strong>Location Type ID:</strong></span>\n";
    echo "                      </div>\n";
    echo "                      <div class=\"col-md-10 col-sm-10 col-lg-10 col-xs-10 text-left form-group\">\n";
    echo "                          <select name=\"strLocTypeID\" id=\"strLocTypeID\" readonly/>&nbsp;\n";
    echo " <option value=\"-----\" class=\"selectors All\">-----</option>\n";
    echo " <option value=\"101\" class=\"selectors Building\">Building</option>\n";
    echo " <option value=\"1275\" class=\"selectors Building\">BUILDING</option>\n";
    echo " <option value=\"1069\" class=\"selectors Building\">CABINET</option>\n";
    echo " <option value=\"1071\" class=\"selectors Building\">CARRIER COLLO</option>\n";
    echo " <option value=\"1072\" class=\"selectors Building\">CARRIER HOTEL</option>\n";
    echo " <option value=\"1073\" class=\"selectors Building\">CARRIER PREM</option>\n";
    echo " <option value=\"1074\" class=\"selectors Building\">CELL SITE</option>\n";
    echo " <option value=\"1075\" class=\"selectors Building\">CENTRAL OFFICE</option>\n";
    echo " <option value=\"1076\" class=\"selectors Building\">CEV</option>\n";
    echo " <option value=\"1077\" class=\"selectors Building\">CUE</option>\n";
    echo " <option value=\"1078\" class=\"selectors Building\">CUSTOMER PREM</option>\n";
    echo " <option value=\"1079\" class=\"selectors Building\">COMMUNITY DIAL OFFICE</option>\n";
    echo " <option value=\"1080\" class=\"selectors Building\">Customer Site</option>\n";
    echo " <option value=\"1081\" class=\"selectors Building\">DATA CENTER</option>\n";
    echo " <option value=\"1082\" class=\"selectors Building\">DIGITAL LOOP CARRIER</option>\n";
    echo " <option value=\"1083\" class=\"selectors Building\">HUT</option>\n";
    echo " <option value=\"1084\" class=\"selectors Building\">IRU COLLO</option>\n";
    echo " <option value=\"1085\" class=\"selectors Building\">IRU HUT</option>\n";
    echo " <option value=\"1086\" class=\"selectors Building\">KDL POP</option>\n";
    echo " <option value=\"1087\" class=\"selectors Building\">METRONET</option>\n";
    echo " <option value=\"1088\" class=\"selectors Building\">MTSO</option>\n";
    echo " <option value=\"1089\" class=\"selectors Building\">MULTI-TENANT</option>\n";
    echo " <option value=\"1090\" class=\"selectors Building\">OTHER</option>\n";
    echo " <option value=\"1091\" class=\"selectors Building\">REGEN</option>\n";
    echo " <option value=\"1092\" class=\"selectors Building\">REMOTE</option>\n";
    echo " <option value=\"1093\" class=\"selectors Building\">SCHOOL</option>\n";
    echo " <option value=\"1094\" class=\"selectors Building\">SITE</option>\n";
    echo " <option value=\"1095\" class=\"selectors Building\">WIRELESS SITE</option>\n";
    echo " <option value=\"1096\" class=\"selectors Building\">WXN BUILDING</option>\n";
    echo " <option value=\"1097\" class=\"selectors Building\">WXN HUT</option>\n";
    echo " <option value=\"1098\" class=\"selectors Building\">WXN LEASED SUITE</option>\n";
    echo " <option value=\"1099\" class=\"selectors Building\">TESTING</option>\n";
    echo " <option value=\"1381\" class=\"selectors Building\">Regen</option>\n";
    echo " <option value=\"192\" class=\"selectors Customer\">End User</option>\n";
    echo " <option value=\"1276\" class=\"selectors Customer\">END USER</option>\n";
    echo " <option value=\"1100\" class=\"selectors Customer\">VENDOR/CUSTOMER LOCATION</option>\n";
    echo " <option value=\"191\" class=\"selectors Customer\">CUSTOMER LOCATION</option>\n";
    echo " <option value=\"1347\" class=\"selectors IntlSwitching\">ONE-WAY INCOMING SWITCH TO A PABX NETWRK</option>\n";
    echo " <option value=\"1348\" class=\"selectors IntlSwitching\">LOCAL TRANSIT OFFICE</option>\n";
    echo " <option value=\"1349\" class=\"selectors IntlSwitching\">COMBINED DDI AND LOCAL TRANSIT OFF</option>\n";
    echo " <option value=\"1350\" class=\"selectors IntlSwitching\">COMBINED LOCAL TRANSIT, END OFFICE</option>\n";
    echo " <option value=\"1107\" class=\"selectors IntlSwitching\">Remote Tandem and Multi-Function EO</option>\n";
    echo " <option value=\"1352\" class=\"selectors IntlSwitching\">REMOTE TANDEM AND MULTI-FUNCTION EO</option>\n";
    echo " <option value=\"1353\" class=\"selectors IntlSwitching\">INDIVIDUAL REMOTE TANDEM</option>\n";
    echo " <option value=\"1104\" class=\"selectors IntlSwitching\">Individual Remote Tandem</option>\n";
    echo " <option value=\"1351\" class=\"selectors IntlSwitching\">INCOMING SWITCH TO A PAGING NETWORK</option>\n";
    echo " <option value=\"1366\" class=\"selectors MiscSwitching\">ANNOUNCEMENT MACHINE</option>\n";
    echo " <option value=\"1306\" class=\"selectors MiscSwitching\">OTHER SWITCHING TERM ENTITIES INCL IMTS</option>\n";
    echo " <option value=\"1110\" class=\"selectors MiscSwitching\">Automatic Intercept System : FAS</option>\n";
    echo " <option value=\"1116\" class=\"selectors MiscSwitching\">Gateway-- Trunk</option>\n";
    echo " <option value=\"1117\" class=\"selectors MiscSwitching\">Gateway--Line/Access</option>\n";
    echo " <option value=\"1118\" class=\"selectors MiscSwitching\">Gateway-Access (Gnx)</option>\n";
    echo " <option value=\"1120\" class=\"selectors MiscSwitching\">Gateway-Trunk (GTx,GRx)</option>\n";
    echo " <option value=\"1123\" class=\"selectors MiscSwitching\">Message Trunk Interface</option>\n";
    echo " <option value=\"1134\" class=\"selectors MiscSwitching\">Time Distributor</option>\n";
    echo " <option value=\"1135\" class=\"selectors MiscSwitching\">Weather Distributor</option>\n";
    echo " <option value=\"1225\" class=\"selectors MiscSwitching\">Announcement machine</option>\n";
    echo " <option value=\"1232\" class=\"selectors MiscSwitching\">Overflow for X (a) X and (x) MD</option>\n";
    echo " <option value=\"1233\" class=\"selectors MiscSwitching\">Overflow for X(x)X X(x)Y (x)MD</option>\n";
    echo " <option value=\"1396\" class=\"selectors MiscSwitching\">Message Trunk Interface - (x)MD</option>\n";
    echo " <option value=\"1227\" class=\"selectors MiscSwitching\">IXC POT</option>\n";
    echo " <option value=\"1229\" class=\"selectors MiscSwitching\">MESSAGE TRUNK INTERFACE OVERFLOW</option>\n";
    echo " <option value=\"1412\" class=\"selectors MiscSwitching\">NETWORK TERMINATION INTERFACE</option>\n";
    echo " <option value=\"1413\" class=\"selectors MiscSwitching\">PACKET TANDEM SWITCH</option>\n";
    echo " <option value=\"1404\" class=\"selectors MiscSwitching\">GATEWAY - Trunk Gateway GT(x)   or GR(x)</option>\n";
    echo " <option value=\"1475\" class=\"selectors MiscSwitching\">Trunk Gateway</option>\n";
    echo " <option value=\"1477\" class=\"selectors MiscSwitching\">Line/Access Gateway</option>\n";
    echo " <option value=\"1108\" class=\"selectors MiscSwitching\">Announcement Machine</option>\n";
    echo " <option value=\"1111\" class=\"selectors MiscSwitching\">Centrex (Central Office)</option>\n";
    echo " <option value=\"1113\" class=\"selectors MiscSwitching\">DISTRIBUTORS</option>\n";
    echo " <option value=\"1114\" class=\"selectors MiscSwitching\">Emergency (911 Service)</option>\n";
    echo " <option value=\"1119\" class=\"selectors MiscSwitching\">SIGNALING GATEWAY</option>\n";
    echo " <option value=\"1124\" class=\"selectors MiscSwitching\">MESSAGE TRUNK INTERFACE</option>\n";
    echo " <option value=\"1126\" class=\"selectors MiscSwitching\">OPTICAL LINE TERMINATOR</option>\n";
    echo " <option value=\"1127\" class=\"selectors MiscSwitching\">Other Distributors</option>\n";
    echo " <option value=\"1128\" class=\"selectors MiscSwitching\">Other Switching term entities incl IMTS</option>\n";
    echo " <option value=\"1129\" class=\"selectors MiscSwitching\">Overflow Code X(x)Y</option>\n";
    echo " <option value=\"1130\" class=\"selectors MiscSwitching\">Overflow Code X(x)Z</option>\n";
    echo " <option value=\"1435\" class=\"selectors MiscSwitching\">TRUNK GATEWAY</option>\n";
    echo " <option value=\"1437\" class=\"selectors MiscSwitching\">LINE/ACCESS GATEWAY</option>\n";
    echo " <option value=\"1255\" class=\"selectors MiscSwitching\">TRUNK GATEWAY</option>\n";
    echo " <option value=\"1263\" class=\"selectors MiscSwitching\">LINE/ACCESS GATEWAY</option>\n";
    echo " <option value=\"1295\" class=\"selectors MiscSwitching\">CENTREX (CENTRAL OFFICE)</option>\n";
    echo " <option value=\"1296\" class=\"selectors MiscSwitching\">AUTOMATIC DISTRIBUTOR</option>\n";
    echo " <option value=\"1297\" class=\"selectors MiscSwitching\">TIME DISTRIBUTOR</option>\n";
    echo " <option value=\"1298\" class=\"selectors MiscSwitching\">WEATHER DISTRIBUTOR</option>\n";
    echo " <option value=\"1299\" class=\"selectors MiscSwitching\">OTHER DISTRIBUTORS</option>\n";
    echo " <option value=\"1300\" class=\"selectors MiscSwitching\">EMERGENCY (911 SERVICE)</option>\n";
    echo " <option value=\"1301\" class=\"selectors MiscSwitching\">AUTOMATIC INTERCEPT SYSTEM : FAS</option>\n";
    echo " <option value=\"1302\" class=\"selectors MiscSwitching\">COMBINED OPERATOR, TROUBLE, M/C INTERCEP</option>\n";
    echo " <option value=\"1303\" class=\"selectors MiscSwitching\">POSITION LINK FRAME</option>\n";
    echo " <option value=\"1304\" class=\"selectors MiscSwitching\">RATE AND QUOTE SYSTEM</option>\n";
    echo " <option value=\"1305\" class=\"selectors MiscSwitching\">TSPS COMMON CONTROL UNIT</option>\n";
    echo " <option value=\"1109\" class=\"selectors MiscSwitching\">Automatic Distributor</option>\n";
    echo " <option value=\"1354\" class=\"selectors NonBuilding\">BOUNDARY</option>\n";
    echo " <option value=\"1151\" class=\"selectors NonBuilding\">Repeater Housing</option>\n";
    echo " <option value=\"1356\" class=\"selectors NonBuilding\">JUNCTION</option>\n";
    echo " <option value=\"1357\" class=\"selectors NonBuilding\">MANHOLE</option>\n";
    echo " <option value=\"1358\" class=\"selectors NonBuilding\">POLE</option>\n";
    echo " <option value=\"1359\" class=\"selectors NonBuilding\">RADIO</option>\n";
    echo " <option value=\"1360\" class=\"selectors NonBuilding\">REPEATER</option>\n";
    echo " <option value=\"1361\" class=\"selectors NonBuilding\">TOLL STATION</option>\n";
    echo " <option value=\"1362\" class=\"selectors NonBuilding\">OTHER</option>\n";
    echo " <option value=\"1363\" class=\"selectors NonBuilding\">NON-BELLCORE CUSTOMER NONBUILDING LOC</option>\n";
    echo " <option value=\"1368\" class=\"selectors NonBuilding\">CABINET</option>\n";
    echo " <option value=\"1136\" class=\"selectors NonBuilding\">Boundary</option>\n";
    echo " <option value=\"1137\" class=\"selectors NonBuilding\">Cabinet</option>\n";
    echo " <option value=\"1140\" class=\"selectors NonBuilding\">End Point</option>\n";
    echo " <option value=\"1144\" class=\"selectors NonBuilding\">Junction</option>\n";
    echo " <option value=\"1145\" class=\"selectors NonBuilding\">Manhole</option>\n";
    echo " <option value=\"1149\" class=\"selectors NonBuilding\">Radio</option>\n";
    echo " <option value=\"1230\" class=\"selectors NonBuilding\">Other</option>\n";
    echo " <option value=\"1386\" class=\"selectors NonBuilding\">PEDESTAL</option>\n";
    echo " <option value=\"1138\" class=\"selectors NonBuilding\">CELL TOWER</option>\n";
    echo " <option value=\"1139\" class=\"selectors NonBuilding\">DO_NOT_USE</option>\n";
    echo " <option value=\"1141\" class=\"selectors NonBuilding\">FIBER NODE</option>\n";
    echo " <option value=\"1142\" class=\"selectors NonBuilding\">HANDHOLE</option>\n";
    echo " <option value=\"1143\" class=\"selectors NonBuilding\">Hut</option>\n";
    echo " <option value=\"1146\" class=\"selectors NonBuilding\">Non-Bellcore customer nonbuilding loc</option>\n";
    echo " <option value=\"1147\" class=\"selectors NonBuilding\">PAD</option>\n";
    echo " <option value=\"1148\" class=\"selectors NonBuilding\">Pole</option>\n";
    echo " <option value=\"1150\" class=\"selectors NonBuilding\">Repeater</option>\n";
    echo " <option value=\"1355\" class=\"selectors NonBuilding\">END POINT</option>\n";
    echo " <option value=\"1346\" class=\"selectors NonSwitching\">TEST OR SERVICE POSITION</option>\n";
    echo " <option value=\"1364\" class=\"selectors NonSwitching\">PAIR GAIN CENTRAL OFFICE TERMINAL EQMT</option>\n";
    echo " <option value=\"1367\" class=\"selectors NonSwitching\">FACILITY/CIRCUIT POI</option>\n";
    echo " <option value=\"1156\" class=\"selectors NonSwitching\">Administrative Entities</option>\n";
    echo " <option value=\"1163\" class=\"selectors NonSwitching\">Exchange Switchroom</option>\n";
    echo " <option value=\"1166\" class=\"selectors NonSwitching\">Facility/Circuit POI (Wxx)</option>\n";
    echo " <option value=\"1168\" class=\"selectors NonSwitching\">Facility/Circuit Point of Interface -POI</option>\n";
    echo " <option value=\"1169\" class=\"selectors NonSwitching\">Frames (all types)</option>\n";
    echo " <option value=\"1170\" class=\"selectors NonSwitching\">Maintenance Group</option>\n";
    echo " <option value=\"1171\" class=\"selectors NonSwitching\">Misc Non-switching Entities</option>\n";
    echo " <option value=\"1172\" class=\"selectors NonSwitching\">Miscellaneous Optical Eqmt</option>\n";
    echo " <option value=\"1179\" class=\"selectors NonSwitching\">Radio Tower collocated on building</option>\n";
    echo " <option value=\"1183\" class=\"selectors NonSwitching\">Service Center</option>\n";
    echo " <option value=\"1185\" class=\"selectors NonSwitching\">Software Cross-connectable entities</option>\n";
    echo " <option value=\"1187\" class=\"selectors NonSwitching\">Test or Service Position</option>\n";
    echo " <option value=\"1188\" class=\"selectors NonSwitching\">Toll Test Room (or Board)</option>\n";
    echo " <option value=\"1235\" class=\"selectors NonSwitching\">Misc Non-Switching Entities</option>\n";
    echo " <option value=\"1377\" class=\"selectors NonSwitching\">Session Border Controller - BS(n)</option>\n";
    echo " <option value=\"1389\" class=\"selectors NonSwitching\">Misc Optical Equip</option>\n";
    echo " <option value=\"1394\" class=\"selectors NonSwitching\">Facility/Circuit POI - W(x)(x)</option>\n";
    echo " <option value=\"1226\" class=\"selectors NonSwitching\">IC POT FOR FAC/CKT TERMINATING EQUIPMENT</option>\n";
    echo " <option value=\"1234\" class=\"selectors NonSwitching\">REMOTE LINE - RT LINE SIDE</option>\n";
    echo " <option value=\"1382\" class=\"selectors NonSwitching\">Remote Line Entity- RL(n) and RL(a)</option>\n";
    echo " <option value=\"1399\" class=\"selectors NonSwitching\">Customer Prem Equip - N(x)(x)</option>\n";
    echo " <option value=\"1400\" class=\"selectors NonSwitching\">REPEATER/REGENERATOR</option>\n";
    echo " <option value=\"1405\" class=\"selectors NonSwitching\">PROCESSOR/SERVER GROUPING</option>\n";
    echo " <option value=\"1409\" class=\"selectors NonSwitching\">Miscellaneous Optical Equip - O(n)(x)</option>\n";
    echo " <option value=\"1411\" class=\"selectors NonSwitching\">ECHO CANCELLER</option>\n";
    echo " <option value=\"1419\" class=\"selectors NonSwitching\">Processor/Server Grouping D(n)(n)</option>\n";
    echo " <option value=\"1407\" class=\"selectors NonSwitching\">H(x)(x) - ILEC Misc NonSwitching Entity</option>\n";
    echo " <option value=\"1418\" class=\"selectors NonSwitching\">Misc Optical Equip - O(x)(x)</option>\n";
    echo " <option value=\"1476\" class=\"selectors NonSwitching\">Call Agent/MSC Server</option>\n";
    echo " <option value=\"1436\" class=\"selectors NonSwitching\">CALL AGENT/MSC SERVER</option>\n";
    echo " <option value=\"1154\" class=\"selectors NonSwitching\">ACI CELL SITE</option>\n";
    echo " <option value=\"1155\" class=\"selectors NonSwitching\">ACCESS SERVICE TERMINATION</option>\n";
    echo " <option value=\"1157\" class=\"selectors NonSwitching\">BASE STATION/RADIO EQUIPMENT</option>\n";
    echo " <option value=\"1159\" class=\"selectors NonSwitching\">Concentrator</option>\n";
    echo " <option value=\"1160\" class=\"selectors NonSwitching\">Customer Premises Equipment</option>\n";
    echo " <option value=\"1162\" class=\"selectors NonSwitching\">DISTRIBUTION NODE (CABLE TV)</option>\n";
    echo " <option value=\"1173\" class=\"selectors NonSwitching\">MISCELLANEOUS OPTICAL EQUIPMENT</option>\n";
    echo " <option value=\"1174\" class=\"selectors NonSwitching\">Pair Gain Central Office Terminal Eqmt</option>\n";
    echo " <option value=\"1175\" class=\"selectors NonSwitching\">PERSONNEL SUPPORT CENTERS OAM&amp;P</option>\n";
    echo " <option value=\"1176\" class=\"selectors NonSwitching\">Processor (Applique) Grouping</option>\n";
    echo " <option value=\"1177\" class=\"selectors NonSwitching\">Processor/Server Grouping</option>\n";
    echo " <option value=\"1178\" class=\"selectors NonSwitching\">REMOTE LINE TERMINATION</option>\n";
    echo " <option value=\"1182\" class=\"selectors NonSwitching\">SONET NODE</option>\n";
    echo " <option value=\"1184\" class=\"selectors NonSwitching\">SESSION BORDER CONTROLLER/BORDER ELEMENT</option>\n";
    echo " <option value=\"1256\" class=\"selectors NonSwitching\">CALL AGENT/MSC SERVER</option>\n";
    echo " <option value=\"1284\" class=\"selectors NonSwitching\">ADMINISTRATIVE ENTITIES (SCP)</option>\n";
    echo " <option value=\"1285\" class=\"selectors NonSwitching\">PROCESSOR (APPLIQUE) GROUPING</option>\n";
    echo " <option value=\"1286\" class=\"selectors NonSwitching\">EXCHANGE SWITCHROOM</option>\n";
    echo " <option value=\"1287\" class=\"selectors NonSwitching\">FRAMES (ALL TYPES)</option>\n";
    echo " <option value=\"1288\" class=\"selectors NonSwitching\">MISC NON-SWITCHING ENTITIES</option>\n";
    echo " <option value=\"1289\" class=\"selectors NonSwitching\">SOFTWARE CROSS-CONNECTABLE ENTITIES</option>\n";
    echo " <option value=\"1290\" class=\"selectors NonSwitching\">MAINTENANCE GROUP</option>\n";
    echo " <option value=\"1291\" class=\"selectors NonSwitching\">CUSTOMER PREMISES EQUIPMENT</option>\n";
    echo " <option value=\"1292\" class=\"selectors NonSwitching\">RADIO TOWER COLOCATED ON BUILDING</option>\n";
    echo " <option value=\"1293\" class=\"selectors NonSwitching\">SERVICE CENTER</option>\n";
    echo " <option value=\"1294\" class=\"selectors NonSwitching\">TOLL TEST ROOM (OR BOARD)</option>\n";
    echo " <option value=\"1190\" class=\"selectors Other\">Acc Ckt Term in a LEC Centrex by an IC</option>\n";
    echo " <option value=\"1282\" class=\"selectors Other\">ACC CKT TERM IN A LEC CENTREX BY AN IC</option>\n";
    echo " <option value=\"1198\" class=\"selectors Other\">IXC</option>\n";
    echo " <option value=\"1200\" class=\"selectors Other\">MD Overflow</option>\n";
    echo " <option value=\"1202\" class=\"selectors Other\">Overflow for X (a) X and (x) MD</option>\n";
    echo " <option value=\"1203\" class=\"selectors Other\">Overflow for X(x)X X(x)Y (x)MD</option>\n";
    echo " <option value=\"1281\" class=\"selectors Other\">OVERFLOW FOR X(X)X X(X)Y (X)MD</option>\n";
    echo " <option value=\"1383\" class=\"selectors Other\">CONCENTRATOR</option>\n";
    echo " <option value=\"1384\" class=\"selectors Other\">BTI COLO IN LEC/IXC POP</option>\n";
    echo " <option value=\"1385\" class=\"selectors Other\">CUSTOMER COLO IN BTI POP</option>\n";
    echo " <option value=\"1191\" class=\"selectors Other\">CAGELESS COLO</option>\n";
    echo " <option value=\"1192\" class=\"selectors Other\">CUSTOMER COLO</option>\n";
    echo " <option value=\"1193\" class=\"selectors Other\">DEDICATED CPE</option>\n";
    echo " <option value=\"1194\" class=\"selectors Other\">FICTITIOUS CARRIER ETHERNET ROUTER</option>\n";
    echo " <option value=\"1196\" class=\"selectors Other\">ILEC</option>\n";
    echo " <option value=\"1197\" class=\"selectors Other\">IXC POT</option>\n";
    echo " <option value=\"1199\" class=\"selectors Other\">LEC CONSORTIUM SERVING AS A POT</option>\n";
    echo " <option value=\"1201\" class=\"selectors Other\">OCC</option>\n";
    echo " <option value=\"1204\" class=\"selectors Other\">PHYSICAL COLO</option>\n";
    echo " <option value=\"1205\" class=\"selectors Other\">POINT OF PRESENCE</option>\n";
    echo " <option value=\"1206\" class=\"selectors Other\">REGENERATOR</option>\n";
    echo " <option value=\"1207\" class=\"selectors Other\">TERMINAL</option>\n";
    echo " <option value=\"1208\" class=\"selectors Other\">VIRTUAL COLO</option>\n";
    echo " <option value=\"1278\" class=\"selectors Other\">IC POT FOR FAC/CKT TERMINATING EQUIPMENT</option>\n";
    echo " <option value=\"1279\" class=\"selectors Other\">MESSAGE TRUNK INTERFACE OVERFLOW</option>\n";
    echo " <option value=\"1280\" class=\"selectors Other\">OVERFLOW FOR X (A) X AND (X) MD</option>\n";
    echo " <option value=\"1195\" class=\"selectors Other\">IC POT for Fac/Ckt Terminating Equipment</option>\n";
    echo " <option value=\"193\" class=\"selectors Room\">Room</option>\n";
    echo " <option value=\"1277\" class=\"selectors Room\">ROOM</option>\n";
    echo " <option value=\"1210\" class=\"selectors Room\">GROOMS</option>\n";
    echo " <option value=\"1307\" class=\"selectors Switchboard\">CAMA BOARD</option>\n";
    echo " <option value=\"1023\" class=\"selectors Switchboard\">TSPS Board</option>\n";
    echo " <option value=\"1309\" class=\"selectors Switchboard\">COMBINED TOLL, DSA AND CAMA</option>\n";
    echo " <option value=\"1310\" class=\"selectors Switchboard\">DIRECTORY ASST (INFORMATION)</option>\n";
    echo " <option value=\"1311\" class=\"selectors Switchboard\">INTERCEPT BOARD</option>\n";
    echo " <option value=\"1312\" class=\"selectors Switchboard\">COMBINED DIR ASST, INTERCEPT AND COMPLET</option>\n";
    echo " <option value=\"1313\" class=\"selectors Switchboard\">INWARD TOLL BOARD</option>\n";
    echo " <option value=\"1314\" class=\"selectors Switchboard\">MANUAL SWITCHBOARD</option>\n";
    echo " <option value=\"1315\" class=\"selectors Switchboard\">OVERSEAS TOLL BOARD</option>\n";
    echo " <option value=\"1316\" class=\"selectors Switchboard\">RATE AND ROUTE DESK</option>\n";
    echo " <option value=\"1317\" class=\"selectors Switchboard\">SERVICE OBSERVING SWITCHBOARD</option>\n";
    echo " <option value=\"1318\" class=\"selectors Switchboard\">SPCL: CONF, MOBILE, MARINE SOST</option>\n";
    echo " <option value=\"1319\" class=\"selectors Switchboard\">TELECONFERENCE BOARD</option>\n";
    echo " <option value=\"1320\" class=\"selectors Switchboard\">TEL COMPANY PBX (OFFICIAL)</option>\n";
    echo " <option value=\"1321\" class=\"selectors Switchboard\">TOPS SYSTEM</option>\n";
    echo " <option value=\"1322\" class=\"selectors Switchboard\">TSPS BOARD</option>\n";
    echo " <option value=\"1323\" class=\"selectors Switchboard\">TRAFFIC SERVICE POSITION (UNIVERSAL TSP)</option>\n";
    echo " <option value=\"1324\" class=\"selectors Switchboard\">OTHER SWITCHBOARD AND DESK ENTITIES</option>\n";
    echo " <option value=\"1345\" class=\"selectors Switchboard\">TOLL BOARD (THROUGH, OUTWARD)</option>\n";
    echo " <option value=\"1022\" class=\"selectors Switchboard\">TOPS System</option>\n";
    echo " <option value=\"1308\" class=\"selectors Switchboard\">DIAL SERVICE ASSISTANCE BOARD</option>\n";
    echo " <option value=\"1030\" class=\"selectors Switching\">CALL AGENT/MSC SERVER</option>\n";
    echo " <option value=\"1033\" class=\"selectors Switching\">End Office - Crossbar</option>\n";
    echo " <option value=\"1034\" class=\"selectors Switching\">End Office - Electronic Analog</option>\n";
    echo " <option value=\"1035\" class=\"selectors Switching\">End Office - Electronic Digital</option>\n";
    echo " <option value=\"1036\" class=\"selectors Switching\">End Office - NXX Entity</option>\n";
    echo " <option value=\"1037\" class=\"selectors Switching\">End Office - Packet</option>\n";
    echo " <option value=\"1041\" class=\"selectors Switching\">PACKET FRAME RELAY SWITCH</option>\n";
    echo " <option value=\"1042\" class=\"selectors Switching\">IXC POT</option>\n";
    echo " <option value=\"1043\" class=\"selectors Switching\">MOBILE/SWITCHING (MTSO)</option>\n";
    echo " <option value=\"1046\" class=\"selectors Switching\">OPTICAL SWITCH</option>\n";
    echo " <option value=\"1047\" class=\"selectors Switching\">PACKET END OFFICE</option>\n";
    echo " <option value=\"1048\" class=\"selectors Switching\">PACKET TANDEM SWITCH</option>\n";
    echo " <option value=\"1052\" class=\"selectors Switching\">REMOTE PACKET END OFFICE</option>\n";
    echo " <option value=\"1055\" class=\"selectors Switching\">SWITCH</option>\n";
    echo " <option value=\"1068\" class=\"selectors Switching\">WIRELESS/CELLULAR</option>\n";
    echo " <option value=\"1325\" class=\"selectors Switching\">END OFFICE - CROSSBAR</option>\n";
    echo " <option value=\"1326\" class=\"selectors Switching\">END OFFICE - STEP-BY-STEP</option>\n";
    echo " <option value=\"1327\" class=\"selectors Switching\">END OFFICE - ELECTRONIC ANALOG</option>\n";
    echo " <option value=\"1328\" class=\"selectors Switching\">END OFFICE - ELECTRONIC DIGITAL</option>\n";
    echo " <option value=\"1329\" class=\"selectors Switching\">END OFFICE - REMOTE SWITCHING SYSTEMS</option>\n";
    echo " <option value=\"1330\" class=\"selectors Switching\">END OFFICE - NXX ENTITY</option>\n";
    echo " <option value=\"1331\" class=\"selectors Switching\">TANDEM OFFICE - INDIVIDUAL TANDEM</option>\n";
    echo " <option value=\"1332\" class=\"selectors Switching\">TANDEM OFFICE - TANDEM/TANDEM</option>\n";
    echo " <option value=\"1333\" class=\"selectors Switching\">TANDEM OFFICE - TANDEM/SWITCHBOARD</option>\n";
    echo " <option value=\"1334\" class=\"selectors Switching\">TANDEM OFFICE - OPR SVC TANDEM/END OFFIC</option>\n";
    echo " <option value=\"1335\" class=\"selectors Switching\">TANDEM OFFICE - ELEC TANDEM PVT NETWORK</option>\n";
    echo " <option value=\"1336\" class=\"selectors Switching\">MULTI-FUNCTION - COMBINATION SWITCH</option>\n";
    echo " <option value=\"1337\" class=\"selectors Switching\">REMOTE LINE - RT LINE SIDE</option>\n";
    echo " <option value=\"1338\" class=\"selectors Switching\">PACKET - DIGITAL PACKET DEVICE</option>\n";
    echo " <option value=\"1339\" class=\"selectors Switching\">CELL RELAY - BROADBAND</option>\n";
    echo " <option value=\"1340\" class=\"selectors Switching\">VIDEO - ANALOG/DIGITAL</option>\n";
    echo " <option value=\"1341\" class=\"selectors Switching\">CELLULAR (MTSO) - BELLBOY CONTROL TERMIN</option>\n";
    echo " <option value=\"1342\" class=\"selectors Switching\">SPECIAL SWITCHING APPLICATIONS - CCS</option>\n";
    echo " <option value=\"1343\" class=\"selectors Switching\">SPECIAL SWITCHING APPL - CONCENTRATOR</option>\n";
    echo " <option value=\"1344\" class=\"selectors Switching\">SPECIAL SWITCHING APPL - TELETYPE SWC SY</option>\n";
    echo " <option value=\"1031\" class=\"selectors Switching\">Cell Relay - Broadband</option>\n";
    echo " <option value=\"1032\" class=\"selectors Switching\">Cellular (MTSO) - Bellboy Control Termin</option>\n";
    echo " <option value=\"1039\" class=\"selectors Switching\">End Office - Remote Switching Systems</option>\n";
    echo " <option value=\"1040\" class=\"selectors Switching\">End Office - Step-by-Step</option>\n";
    echo " <option value=\"1044\" class=\"selectors Switching\">Multi-Function - Combination Switch</option>\n";
    echo " <option value=\"1049\" class=\"selectors Switching\">POI SWITCH CLLI</option>\n";
    echo " <option value=\"1050\" class=\"selectors Switching\">Packet - Digital Packet Device</option>\n";
    echo " <option value=\"1051\" class=\"selectors Switching\">Packet - Packet End Office</option>\n";
    echo " <option value=\"1053\" class=\"selectors Switching\">Remote Line - RT Line Side</option>\n";
    echo " <option value=\"1054\" class=\"selectors Switching\">Remote Switching System</option>\n";
    echo " <option value=\"1056\" class=\"selectors Switching\">Special Switching Appl - Concentrator</option>\n";
    echo " <option value=\"1057\" class=\"selectors Switching\">Special Switching Appl - Teletype Swc Sy</option>\n";
    echo " <option value=\"1058\" class=\"selectors Switching\">Special Switching Applications - CCS</option>\n";
    echo " <option value=\"1059\" class=\"selectors Switching\">Switching</option>\n";
    echo " <option value=\"1061\" class=\"selectors Switching\">Tandem Office - Elec Tandem Pvt Network</option>\n";
    echo " <option value=\"1062\" class=\"selectors Switching\">Tandem Office - Individual Tandem</option>\n";
    echo " <option value=\"1063\" class=\"selectors Switching\">Tandem Office - Opr Svc Tandem/End Offic</option>\n";
    echo " <option value=\"1065\" class=\"selectors Switching\">Tandem Office - Tandem/Switchboard</option>\n";
    echo " <option value=\"1066\" class=\"selectors Switching\">Tandem Office - Tandem/Tandem</option>\n";
    echo " <option value=\"1067\" class=\"selectors Switching\">Video - Analog/Digital</option>\n";
    echo " <option value=\"1257\" class=\"selectors Switching\">Packet End Office</option>\n";
    echo " <option value=\"1258\" class=\"selectors Switching\">Remote Packet End Office</option>\n";
    echo " <option value=\"1259\" class=\"selectors Switching\">Packet Tandem Switch</option>\n";
    echo " <option value=\"1380\" class=\"selectors Switching\">IX Carrier POT</option>\n";
    echo " <option value=\"1395\" class=\"selectors Switching\">Call Agent - CA(x)</option>\n";
    echo " <option value=\"1224\" class=\"selectors Switching\">ACC CKT TERM IN A LEC CENTREX BY AN IC</option>\n";
    echo " <option value=\"1231\" class=\"selectors Switching\">OTHER SWITCHING TERM ENTITIES INCL IMTS</option>\n";
    echo " <option value=\"1375\" class=\"selectors Switching\">IC POT FOR FAC/CKT TERMINATING EQUIPMENT</option>\n";
    echo " <option value=\"1376\" class=\"selectors Switching\">MISC NON-SWITCHING ENTITIES</option>\n";
    echo " <option value=\"1378\" class=\"selectors Switching\">TEST OR SERVICE POSITION</option>\n";
    echo " <option value=\"1391\" class=\"selectors Switching\">CALL AGENT</option>\n";
    echo " <option value=\"1406\" class=\"selectors Switching\">Digital Packet Device - (x) (x) W</option>\n";
    echo " <option value=\"1420\" class=\"selectors Switching\">Digital Packet Device (x)(x)W</option>\n";
    echo " <option value=\"1397\" class=\"selectors Switching\">ATM Switch  BB(x) [overflow B(a)(n)]</option>\n";
    echo " <option value=\"1029\" class=\"selectors Switching\">ATM SWITCH</option>\n";
    echo "                          </select>\n";
    echo "                      </div>\n";
    echo "                  </div>\n";
    echo "              </div>\n";
    echo "          </div>\n";
    echo "      </div>\n";

In the JavaScript, I’ve got a quick function that repopulates the rather long drop-down menu based on the selected category

// Filter strLocTypeID options based on strLocCategory value
$(document).ready(function () {    
    var allOptions = $('#strLocTypeID option')
    $('#strLocCategory').change(function () {
        $('#strLocTypeID option').remove()

        var classN = $('#strLocCategory option:selected').prop('class');
        var optsCat = allOptions.filter('.' + classN);
        $.each(optsCat, function (i, j) {
            $(j).appendTo('#strLocTypeID');
        });

        var optsAll = allOptions.filter('.All');
        $.each(optsAll, function (i, j) {
            $(j).prependTo('#strLocTypeID');
        });

    });
});

Since it’s possible there are options you’d want to always appear (in my case, it’s just the “—–” to indicate no selection has been made … but there could be real items that fall into each category too), I’ve got an “All” classification that will get popped onto the top of the list.

NodeJS Unit File

For future reference, this is an example unit file for running a NodeJS server with systemd. The NodeJS code we use reads from a local MariaDB, so I’ve added a service dependency for the database server.

Create /etc/systemd/system/nodeserver.service

[Unit]
Description=SiteName Node.js Server
Requires=After=mariadb.service

[Service]
ExecStart=/path/to/binary/for/node /path/to/nodeJS/html/server.js
WorkingDirectory=/path/to/nodeJS/html
Restart=always
RestartSec=30
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=nodejs-sitename
User=web-user
Group=www-group

[Install]
WantedBy=multi-user.target

Use systemctl daemon-reload to register the new unit file, then “systemctl start nodeserver.service” to start the service. Assuming everything works properly, use “systemctl enable nodeserver.service” to have the service start on boot.

LDAP Authentication: Python Flask

This is a quick python script showing how the flask-ldap3-login module can be used to authenticate and gather user attribute values

from flask_ldap3_login import LDAP3LoginManager
from ldap3 import Tls
import ssl

config = dict()

config['LDAP_HOST'] = 'ad.example.com'

# Use SSL unless you are debugging a problem. Clear text port is 389 and tls_ctx needs to be removed from add_server call
config['LDAP_USE_SSL'] = True
config['LDAP_PORT'] = 636

# Base DN
config['LDAP_BASE_DN'] = 'dc=example,dc=com'

# User Base DN, prepended to Base DN
config['LDAP_USER_DN'] = 'ou=UserDN'

# Groups Base DN, prepended to Base DN
config['LDAP_GROUP_DN'] = 'ou=SecurityGroupDN'

# Server will be manually added to establish SSL
config['LDAP_ADD_SERVER'] = False

# Domain component of userprincipal name
config['LDAP_BIND_DIRECT_SUFFIX'] = '@example.com'

# Search scope needs to be subtree
config['LDAP_USER_SEARCH_SCOPE'] = "SUBTREE"

# Attributes to return
config['LDAP_GET_USER_ATTRIBUTES'] = ("mail", "givenName", "sn")

# Setup a LDAP3 Login Manager.
ldap_manager = LDAP3LoginManager()

# Init the mamager with the config since we aren't using an app
ldap_manager.init_config(config)

# TLS settings to establish trust without validating CA issuance chain. 
# Can use CERT_REQUIRED and ca_certs_file with path to cacerts that includes issuing chain
tls_ctx = Tls(
    validate=ssl.CERT_NONE,
    version=ssl.PROTOCOL_TLSv1,
    valid_names=[
        'ad.example.com',
    ]
)

ldap_manager.add_server(
    config.get('LDAP_HOST'),
    config.get('LDAP_PORT'),
    config.get('LDAP_USE_SSL'),
    tls_ctx=tls_ctx
)

# Validate credentials
response = ldap_manager.authenticate_direct_credentials('e0012345', 'P@s5w0rdG03sH3re')
print(response.status)
print(response.user_info)

LDAP Authentication and Authorization: PHP

Blah

<?php
    error_reporting(0);
    #=== FUNCTION ==================================================================
    #      NAME: ldapAuthenticationAndAuthorizationWithAttributes
    #      PARAMETERS:
    #                    $strLDAPHost                   String  LDAP Server URI
    #                    $strUIDAttr                    String  Schema attribute for user ID search
    #                    $strSystemUser                 String  System credential username
    #                    $strSystemPassword             String  System credential password
    #                    $strUserBaseDN                 String  User search LDAP base DN
    #                    $strLogonUserID                String  Input user ID
    #                    $strLogonUserPassword          String  Input user password
    #					 $arrayAttrsToReturn			String	Attributes to be returned
    #                    $strGroupBaseDN                String  (optional) Group search LDAP base DN
    #                    $strGroupNamingAttribute       String  (optional) Schema attribute for group search
    #                    $strMembershipAttr             String  (optional) Schema attribute for group membership
    #                    $strAuthGroup                  String  (optional) Group name
    #     DESCRIPTION: Verify authentication and authorization against AD server.a
    #
    #     RETURNS: array(BindReturnCode, Authorized, array(returnValues))
    #                        BindReturnCode:    -1 indicates LDAP connection failure, -2 indicates system account auth failed, -3 indicates user auth not attempted, >=0 is IANA-registered resultCode values (https://www.iana.org/assignments/ldap-parameters/ldap-parameters.xml#ldap-parameters-6)
    #							NOTE: 0 is successful authentication in IANA-registered resultCode
    #                        Authorized:        0 authorization not attempted, -1 is not a member of the located group, 1 is member of the located group
    #						arrayUserAttributeValues	Array with values of $arrayAttrsToReturn
    #
    #     USAGE: $arrayUserAuthorized = ldapAuthenticationAndAuthorizationWithAttributes("ldaps://ad.example.com","sAMAccountName","ldapquery@example.com", "Sy5t3mP@ssw0rdG03sH3re", "ou=example,dc=example,dc=com", $strInputUserName, $strInputUserPassword, array('givenName', 'sn'), "ou=securitygroups,dc=example,dc=com","cn", "member", "LJRTestGroup")
    #===============================================================================
    function ldapAuthenticationAndAuthorizationWithAttributes($strLDAPHost,$strUIDAttr, $strSystemUser, $strSystemPassword, $strUserBaseDN, $strLogonUserID, $strLogonUserPassword, $arrayAttrsToReturn, $strGroupBaseDN=null, $strGroupNamingAttribute=null, $strMembershipAttr=null, $strAuthGroup=null){
        $arrayAuthResults = array();
        $arrayUserAttributeValues = array();
        // Validate password is not null, otherwise directory servers implementing unauthenticated bind (https://tools.ietf.org/html/rfc4513#section-5.1.2) will return 0 on auth attempts with null password
        if( strlen($strLogonUserPassword) < 1){
            $arrayAuthResults['BindReturnCode'] = -3;
            $arrayAuthResults['Authorized'] = -1;
        }
        else{
            // Connect to the LDAP directory for system ID queries
            $systemDS = ldap_connect($strLDAPHost);
            ldap_set_option($systemDS, LDAP_OPT_PROTOCOL_VERSION, 3);

            if ($systemDS) {
                // Bind with the system ID and find $strLogonUserID FQDN
                $systemBind = ldap_bind($systemDS, $strSystemUser, $strSystemPassword);

                if(ldap_errno($systemDS) == 0){
                    $strLDAPFilter="(&amp;($strUIDAttr=$strLogonUserID))";
                    $result=ldap_search($systemDS,$strUserBaseDN,$strLDAPFilter, $arrayAttrsToReturn);

                    $entry = ldap_first_entry($systemDS, $result);

                    $strFoundUserFQDN= ldap_get_dn($systemDS, $entry);

                    if($strFoundUserFQDN){
                        $userDS = ldap_connect($strLDAPHost);
                        ldap_set_option($userDS, LDAP_OPT_PROTOCOL_VERSION, 3);

                        $userBind = ldap_bind($userDS, $strFoundUserFQDN, $strLogonUserPassword);
                        $arrayAuthResults['BindReturnCode'] = ldap_errno($userDS);

                        ldap_close($userDS);

                        if($arrayAuthResults['BindReturnCode'] == 0){
                        	$objFoundUser = ldap_get_entries($systemDS, $result);
							for($arrayAttrsToReturn as $strAttributeName){
								$arrayUserAttributeValues[$strAttributeName] = $objFoundUser[0][$strAttributeName];

							}
							$arrayAuthResults['AttributeValues'] = $arrayUserAttributeValues;
                            //////////////////////////////////////////////////////////////////////////////////////
                            // If an auth group has been supplied, verify authorization
                            //////////////////////////////////////////////////////////////////////////////////////
                            if($strAuthGroup){
								// Escapes in DN need to be double-escaped or bad search filter error is encountered
                                $strGroupQuery = "(&amp;($strGroupNamingAttribute=$strAuthGroup)($strMembershipAttr=" . str_replace("\\","\\\\", $strFoundUserFQDN) . "))";

                                $groupResult = ldap_search($systemDS,$strGroupBaseDN, $strGroupQuery);
                                $authorisedState = ldap_count_entries($systemDS ,$groupResult);

                                // If a group matching the filter is found, the user is authorised
                                if($authorisedState == 1){
                                    $arrayAuthResults['Authorized'] = 1;
                                }
                                // Otherwise the user is not a member of the group and is not authorised
                                else{
                                    $arrayAuthResults['Authorized'] = -1;
                                }
                            }
                            else{
                                $arrayAuthResults['Authorized'] = 0;
                            }
                            //////////////////////////////////////////////////////////////////////////////////////
                            ldap_close($systemDS);
                        }
                        // If the bind failed, the user has not logged in successfully so they cannot be authorized
                        else{
                            $arrayAuthResults['Authorized'] = -1;

                            ldap_close($systemDS);
                            ldap_close($userDS);
                        }
                    }
                    // User not found in directory
                    else{
                        $arrayAuthResults['BindReturnCode'] = 32;
                        $arrayAuthResults['Authorized'] = -1;
                    }
                }
                // system bind failed
                else{
                    $arrayAuthResults['BindReturnCode'] = -2;
                    $arrayAuthResults['Authorized'] = -1;
                    ldap_close($systemDS);
                }
            }
            // ldap connection failed
            else{
                $arrayAuthResults['BindReturnCode'] = -1;
                $arrayAuthResults['Authorized'] = -1;
            }
        }
        return $arrayAuthResults;
    }

    print "User password not supplied:\n";
    $arrayNullPassword = array();
    $arrayNullPassword = ldapAuthenticationAndAuthorizationWithAttributes("ldaps://ad.example.com","sAMAccountName","ldapquery@example.com", "Sy5t3mP@ssw0rdG03sH3re", "ou=example,dc=example,dc=com", "e0012345", '');
    var_dump($arrayNullPassword);

    print "Bad password:\n";
    $arrayBadPassword = array();
    $arrayBadPassword = ldapAuthenticationAndAuthorizationWithAttributes("ldaps://ad.example.com","sAMAccountName","ldapquery@example.com", "Sy5t3mP@ssw0rdG03sH3re", "ou=example,dc=example,dc=com", "e0012345", 'N0tTh3P@s5w0rd',"ou=SecurityGroups,dc=example,dc=com","cn", "member");
    var_dump($arrayBadPassword);

    print "\nInvalid user:\n";
    $arrayUserNotInDirectory = array();
    $arrayUserNotInDirectory = ldapAuthenticationAndAuthorizationWithAttributes("ldaps://ad.example.com","sAMAccountName","ldapquery@example.com", "Sy5t3mP@ssw0rdG03sH3re", "ou=example,dc=example,dc=com", "xe0012345", 'xDoesN0tM@tt3r');
    var_dump($arrayUserNotInDirectory);

    print "\nGood password without authorization:\n";
    $arrayUserAuthenticated = array();
    $arrayUserAuthenticated = ldapAuthenticationAndAuthorizationWithAttributes("ldaps://ad.example.com","sAMAccountName","ldapquery@example.com", "Sy5t3mP@ssw0rdG03sH3re", "ou=example,dc=example,dc=com", "e0012345", 'Us3rP@s5w0rdG035H3re|Us3rP@s5w0rdG035H3re');
    var_dump($arrayUserAuthenticated);

    print "\nGood password with authorized user:\n";
    $arrayUserAuthorized = array();
    $arrayUserAuthorized = ldapAuthenticationAndAuthorizationWithAttributes("ldaps://ad.example.com","sAMAccountName","ldapquery@example.com", "Sy5t3mP@ssw0rdG03sH3re", "ou=example,dc=example,dc=com", "e0012345", 'Us3rP@s5w0rdG035H3re|Us3rP@s5w0rdG035H3re',"ou=SecurityGroups,dc=example,dc=com","cn", "member", "cfyP_Unix_UnixUsers");
    var_dump($arrayUserAuthorized);

    print "\nGood password with unauthorized user:\n";
    $arrayUserNotAuthorized = array();
    $arrayUserNotAuthorized = ldapAuthenticationAndAuthorizationWithAttributes("ldaps://ad.example.com","sAMAccountName","ldapquery@example.com", "Sy5t3mP@ssw0rdG03sH3re", "ou=example,dc=example,dc=com", "e0012345", 'Us3rP@s5w0rdG035H3re|Us3rP@s5w0rdG035H3re',"ou=SecurityGroups,dc=example,dc=com","cn", "member", "WIN AM Team West");
    var_dump($arrayUserNotAuthorized);

    print "\nBad system account:\n";
    $arrayBadSystemCred = array();
    $arrayBadSystemCred = ldapAuthenticationAndAuthorizationWithAttributes("ldaps://ad.example.com","sAMAccountName","ldapquery@example.com", "xSy5t3mP@ssw0rdG03sH3re", "ou=example,dc=example,dc=com", "e0012345", 'Us3rP@s5w0rdG035H3re|Us3rP@s5w0rdG035H3re');
    var_dump($arrayBadSystemCred);

?>

LDAP Authentication: PHP and Active Directory

This is a very brief function that authenticates a user against Active Directory. Because you can authenticate using a fully qualified DN, sAMAccountName, or userPrincipalName … there’s no need to use a system credential or search for the user provided you’ve got a single domain in your forest (i.e. you know what to prepend to the sAMAccountName or postpend to userPrincipalName).

If you need to perform authorization as well as authentication, you’ll need the user’s FQDN so use the generic LDAP authentication and authorization function.

<?php
    error_reporting(0);
    #=== FUNCTION ==================================================================
    #      NAME: activeDirectoryLDAPAuthentication
    #      PARAMETERS: 
    #                    $strLDAPHost                   String  LDAP Server URI
    #                    $strLogonUserID                String  Input user ID
    #                    $strLogonUserPassword          String  Input user password
    #     DESCRIPTION: Verify authentication againt Active Directory server.
    #     
    #     RETURNS: int BindReturnCode:    -2 indicates LDAP connection failure, -3 indicates user auth not attempted, >=0 is IANA-registered resultCode values (https://www.iana.org/assignments/ldap-parameters/ldap-parameters.xml#ldap-parameters-6)
    #							NOTE: 0 is successful authentication in IANA-registered resultCode
    #
    #     USAGE: $iBindResult = activeDirectoryLDAPAuthentication("ldaps://ad.example.com", $strInputUserName, $strInputUserPassword)
    #===============================================================================
    function activeDirectoryLDAPAuthentication($strLDAPHost, $strLogonUserID, $strLogonUserPassword){
        $iBindReturnCode = null;
        // Validate password is not null, otherwise directory servers implementing unauthenticated bind (https://tools.ietf.org/html/rfc4513#section-5.1.2) will return 0 on auth attempts with null password
        if( strlen($strLogonUserPassword) < 1){
            $iBindReturnCode = -1;
        }
        else{
            $userDS = ldap_connect($strLDAPHost);
            if($userDS){
                ldap_set_option($userDS, LDAP_OPT_PROTOCOL_VERSION, 3);

                $userBind = ldap_bind($userDS, $strLogonUserID . '@example.com', $strLogonUserPassword);
                $iBindReturnCode = ldap_errno($userDS);
                ldap_close($userDS);
            }
            // ldap connection failed
            else{
                $iBindReturnCode = -2;              
            }        
        }
        return $iBindReturnCode;
    }

    $iBadUser = activeDirectoryLDAPAuthentication("ldaps://ad.example.com", "xe0012345", 'N0tTh3P@s5w0rd');
    print "\nInvalid user: $iBadUser\n";

    $iUserAuthenticated = activeDirectoryLDAPAuthentication("ldaps://ad.example.com", "e012345", 'Go0dP@s5w0rdH3r3');
    print "\nGood password: $iUserAuthenticated\n";

    $iBadPassword = activeDirectoryLDAPAuthentication("ldaps://ad.example.com", "e0012345", 'N0tTh3P@s5w0rd');
    print "\nBad password: $iBadPassword\n";

    $iBadHost = activeDirectoryLDAPAuthentication("ldaps://abc.example.com", "e0012345", 'N0tTh3P@s5w0rd');
    print "\nBad host: $iBadHost\n";

?>


Maven Deploy To Github Packages – Error 422: Unprocessable Entity

There is logical consistency to this error, but it would be nice if the error message was a little more indicative of the problem. Scott deployed a JAR to Github Packages. He needed to make a few changes and then was unable to upload the package in his deployment. The error indicted the jar was unable to be transferred to/from Github with error 422. Which was a new one on me — quick search produced the fact 422 is “Unprocessable Entity”. And, yeah, the maven error said exactly that if I’d bothered to read the whole error. I suggested incrementing the version, and the deploy succeeded.

Since GitHub doesn’t allow you to delete public packages, it seems logical that they wouldn’t allow you to overwrite public packages either (if nothing else, I could overwrite it with a text file that says “DELETED” and essentially have deleted the package). Since he was able to deploy the package successfully with a new version tag, it appears that you cannot delete or overwrite public packages. Each new push needs to have a unique tag.

ESP8826 (12e) Multisensor

We’d set up a prototype multi-sensor with an environment sensing kit that Scott picked up at MicroCenter a few years ago. There’s a little LCD display … but we wanted to report readings back to our OpenHAB server. Which required a network connection. Checking out prices for network cards to add to the Uno … well, it wasn’t a cheap add-on. But we found these ESP8266 modules that support 802.11b/g/n and provide the memory/processing for small programs. At about 3$ delivered, that was exactly what we needed.

I ordered a bunch of components to make multi-sensors – pressure sensors, luminescence sensors, temperature/humidity sensors. The sensors connect into a CP2102 ESP8266. The device is powered by a couple of 18650’s in a little box — another buck. There’s some miscellaneous wiring and a little breadboard, too. The total cost for the multi-sensor is about 8.50$. We could add a vibration sensor for another 0.50$, a PIR sensor for 2$, and a UV sensor for 2.50$. That’s 13.50$ for 7 different sensors — and we don’t need seven sensors everywhere.

I kind of want to make a weather station too — add a water level sensor, a precipitation detector, and a wind speed sensor. Those are surprisingly expensive! I want to check out the process to build your own anemometer. But I’d probably buy a nice Davis Anemometer 🙂

Connecting to a WiFi network with the ESP8266 is really easy:

  • Add a library to the Arduino IDE — In the Arduino IDE preferences, add ‘https://arduino.esp8266.com/stable/package_esp8266com_index.json’ into the ‘Additional Board Managers’ URL, then install the ESP8266 library and select the board. I ordered the CP2102 ESP8266 module, and we’re using “” as the board.
  • Configure the WiFi network connection details in your code
  • Compile
  • Upload
  • You’ve on the network!

We’ve used an MQTT library and send sensor readings to our MQTT server.

 

Composer Hangs

I don’t use composer often, and it generally just works … so I don’t know much about it beyond “another package manager”. But every once in a while, it just hangs. Nothing happening, nothing instructive in strace. Fortunately, composer has several levels of verbosity on the output. While the default output is minimal and offers absolutely no clue that it’s doing something … adding -vvv is a nicely verbose output that lets me see that the package install isn’t actually hung. It’s just going to take a long time.

Scraping Calendar Events

We’ve learned the value of engaging with local government — with few people involved in local proceedings, it’s pretty easy for a generally unpopular proposal to seem reasonable. And then we’re all stuck with the generally unpopular regulation. It is a pain, however, to keep manually adding the next Trustee meeting. And there’s no way I’m checking the website daily to find out about any emergency meetings.

Now I’m pulling the events from their Google calendar and creating new meeting items in my Exchange calendar:

  1. Register the app with Google to use the API
  2. Install exchangelib
  3. Copy config.sample to config.py and add personal information
  4. Create a ca.crt file with the CA signing key for your Exchange server (or remove the custom adapter if your server cert is signed by a public key)
  5. Run getCalendarEvents.py and follow the URL to authorize access to your calendar

I’ve tweaked the script to grab events from the school district’s calendar in SchoolPointe too. Now we know when there’s a school board meeting or dress-up day.