Category: Technology

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";

?>


Oracle Password Expiry – Sandbox Server

Oracle 11g seems to ship with password expiry enabled — which is a very good thing for production systems. I’ve even written some code to maintain our system account password (scripts are grabbing the password from a not-clear-text storage facility anyway, so it wasn’t a big deal to add an n-1 password and move the current stashed password into the n-1 column, change the account password, and stash the updated password in the current password location … now my system ID password is updated by a monthly cron job, no one actually knows the password {although anyone could find it, so I would run the password cycle script when individuals leave the group}). But I’m a lot lazier about this stuff in my sandbox. Proof of concept code has clear text passwords. But the server is bound to localhost & there’s no real data in, well, anything.

I started seeing lines in my error log indicating the password would expire. Aaaand that’s how I learned that password expiry was enabled by default now.

[Sat Apr 18 07:42:59 2020] [error] [client 127.0.0.1] PHP Warning: oci_connect(): OCI_SUCCESS_WITH_INFO: ORA-28002: the password will expire within 7 days in /var/www/vhtml/…/file.php on line 191, referer: …

I’m going to disable password expiry because it’s a sandbox. For a real system, obviously, this may not be a stellar idea.

select USERNAME, ACCOUNT_STATUS, PROFILE from dba_users where USERNAME = 'SampleUser';

 

USERNAME ACCOUNT_STATUS PROFILE
SampleUser EXPIRED(GRACE) DEFAULT

 

Note the account status “EXPIRED(GRACE)” — that’s why I am getting the error shown above. Grab the profile name — it’s a sandbox, so 99% sure it’s going to be ‘DEFAULT’ and alter that profile with an unlimited password expiration:

alter profile <profile_name> limit password_life_time UNLIMITED;

Except that didn’t actually stop the error. Turns out you’ve still got to change the password once the account has been flagged as expired (or let the password expire and then unlock the account … but I was looking at the log because I’m debugging something, and I wanted the error to stop *right now*).

alter user SampleUser identified by N3W_P@s5_w0rD;

 

Did you know … you can list the members of your MS Team?

Without any special Administrative rights, you can list the members of the Azure AD groups that are used in MS Teams. If you don’t already have the AzureAD module installed, install it. In Windows, this is:

Install-Module -Name AzureAD

In Linux,you’ll need the preview of Azure AD:

# To run on Linux, you need the preview mode of AzureAD
Register-PackageSource -Trusted -ProviderName 'PowerShellGet' -Name 'Posh Test Gallery' -Location https://www.poshtestgallery.com/api/v2/
Install-Module -Name AzureAD.Standard.Preview
 

Connect to AzureAD. There is a separate command to list the group owners (Get-AzureADGroupOwner). I’ve always found the owner(s) in the member list as well, but it’s technically possible to have entries unique to the owner list.

Connect-AzureAD
Get-AzureADGroup -SearchString "Group Name Here" | Get-AzureADGroupOwner -All $True
Get-AzureADGroup -SearchString "Group Name Here" | Get-AzureADGroupMember -All $True

Redirect the output to a file if you wish to use the results elsewhere, or stash the returned member list in a variable and use Get-AzureADUser to get additional information for the user records.

$objMembers | ForEach-Object -Process {get-azureaduser -objectid $_.ObjectID}

Open Source Methodologies – Design Document Driven

We use design documents at work to ensure a clear understanding between the requestors, product owners, and developers. There’s a request document that outlines what they’re looking to accomplish, we produce a design document that outlines what we’re doing and how that will be accomplished. External dependencies use the design document to implement their required services — if I have a design document that says I’ll pass x (required), y (required), and z (optional) to a WSDL and end up with an object in the application database where a=x, b=y, and, optionally, c=z … they’ll whip up an endpoint that takes the parameters, performs the required actions, and builds the object I need. Once everyone is in agreement that it’s what they want, it’s reasonable (security, ROI), and possible … developers get to work. Tests are built against the documented functionality, and we know we’re done when the tests pass. If the users want something changed, the design document is amended, a quick feasibility/reason-ability review is performed, and development work commences.

I thought of this process after observing some people push PRs for major overhaults into a few open source projects only to have the PRs rejected as, essentially, not the direction “we” want to go. On the other extreme … I’ve made some changes to open source apps — in some cases, those were bug fixes, and I’ve pushed the changes back to the main project. But, when I’ve changed functionality. I’ve made those changes to address a specific need I have, and I leave the changes in my own fork. Which has the detriment of, potentially, not providing useful functionality to the main project. While it’s perfectly reasonable to put a lot of time into a major change that you need anyway (and, potentially, offer those changes back to the community) … it is terrible to put a lot of your time into something for someone else and have it rejected. And while not engaging with the project maintainers to see if they’re interested in my derivative work saves effort for me, it reduces innovation (how many people actually run through all of the forks of a project to see if anything ‘interesting’ happened elsewhere?).

Obviously, the answer isn’t for projects to accept effort just because it’s a significant investment on the contributor’s part — there should be some mechanism for ensuring what you’re about to delve into is something the project maintainers actually want. Which is what made me think of the design documents we use at work.

If a project had a design document that detailed what it waned to do, how it was doing it, and potentially a section for desired future features and functionality … it would provide a guideline to anyone looking to contribute. A change that doesn’t impact functionality (e.g. a bugfix) can be worked on and submitted for inclusion in the project as occurs normally. If you want to change something about how the application works, you first submit a PR against the design document. Outline what you want to do, how you want to do it … maybe even a quick mock-up (I use Pencil Project for mock-ups where I’m uncertain the final project will be approved, HTML web code when I know the project is a go and want a head-start on my development … but I also accept the risk that I ‘wasted’ a few hours building the design document wireframe if the project gets dropped). Want to work on one of the ‘desired future’ items? Modify the design document to include that functionality and how it’ll be implemented. Discussion about the approach refines what you’ll actually be doing, and you’ll understand if the project maintainers are interested in your contribution before dedicating hundreds of hours to development.

Some projects are interested in “bugfixes only” — which can be stated in the contributing guidelines. In this example, I developed a quick script to produce in-scope user lists. I don’t want to include other details about the identified users, I don’t want to find the first n levels of reports, etc. It’s exactly what I needed, and I’m putting it on GitHub as an example — using Python to search an LDAP directory and using recursion with back-linked attributes.

Projects that are open for collaborative contributions, though, can include the design document location in their contributing guidelines. Initial contributions are made against the design document, discussed, and approved or rejected. Once approved, code can be developed to the new design.

Microsoft Teams – Background Images

Teams has had the ability to blur your background for a while – a nice way to obscure “stuff” written on the whiteboard behind your desk or hide the stack of papers and books on your desk. It isolates the foreground – hopefully you – and blurs out the background. You can now overlay the identified foreground with a background image. I currently see this feature in the desktop client – my Linux, mobile, and web clients do not have this feature.

When you are in a meeting and have your camera enabled, click on the ellipses in the meeting control bar and select “Show background effects”

Select one of the images – we’ll load custom images in a bit. Select one of the stock options and click “Apply”

Voila, you’ve been greenscreened over some stock image. One of the most useful cases I see for the background image is a call with vendors. Each individual selects their company logo as a background, and participants have a visual clue who is speaking. But that requires a custom image. Luckily, you can add custom images to the background selection.

Now that you’ve selected a stock image, you’ll have a folder on your computer that holds the image. Open %appdata\Microsoft\Teams\Backgrounds\Uploads

Copy in your custom png files

Repeat the process to select a background image in Teams, and you will see your custom image.

A small file can look blurry – a 1920×1080 image looks decent. My 150×120 little glif … not so great. Also notice that the image is inverted – a bunch of balloons or a sunny beach … works either way. My logo? I need to flip it horizontally or you see a backwards R

Note too – if you want to blur your background, that option has been moved into the background effects. It’s the upper right-hand background – right next to ‘no background image’.

When joining a scheduled meeting, you can adjust the background settings prior to beginning the call using what used to be the background blur slider.

Using ‘Meet now’, this slider does not appear. I voted for the UserVoice suggestion to have a default background setting that would apply to all video call types without one-off configuration for the meeting.