📜 ⬆️ ⬇️

Lobby Admin Cisco Wireless LAN Controller 5500/2500 Standard Replacement

or "I do not like the interface from Cisco - make your own"



The 2500/5500 wireless controllers are used to manage Cisco Aironet access points with LWAPP firmware within the corporate network to provide general security policies, guest access, and support both standard computer clients (laptops, computers, smartphones) and specialized wireless access devices — manual scanners for trading floors, wireless surveillance cameras, etc.

Not so long ago, I was tasked with organizing the possibility of issuing guest Internet access using a Cisco WLC. Access should have been issued by our "reception" - that is, the interface should be as convenient and simple as possible for people far from IT. The creation of guest access itself should have been only part of the process, together with checking documents and issuing a temporary badge and should take no more than 10 seconds.

In the Cisco WLC for user authentication, it is possible to connect an external RADIUS server (this can be a Cisco ISE or Windows NPS - but in our case these options have disappeared) or use the local database of the controller itself. The only limitation of the local database is the maximum number of records in the database: 2048.
')
In our case, this was more than enough, and we decided to use the capabilities of the WLC itself. To create guest accounts, you can create a special administrative account with limited rights Lobby Admin (as the name implies - intended for purposes similar to ours).



Why we did not accept the standard Lobby Admin

Having created such an account, we decided to see the process of creating a guest user by means of Lobby Ambassador (this is the name of this “trimmed” mode).

Step 1. You need to log in - everything is clear, you need to enter a name and password. In principle, the "reception" can log in at the beginning of the day and not close the page, so it will not affect the speed of creation
Step 2. Click the New button.

Step 3. Fill in the form - here you must specify the user name, generate a password, specify the time of action and select the network (guest)


Here it became clear that in 10 seconds there was no way to keep within:


As a result, our reception did not suit the standard interface, which is understandable, the UI in Cisco Web based applications is traditionally not a fountain ...

How we solved the problem

Quite simply, a quick PHP script was written, which we would like to share.
I especially ask you not to peer into the code and not to criticize, a person writes in PHP for the second time in his life (and the third time in general programs) - therefore, the issues of style and security of the script were not considered :).
Script source code
<?php error_reporting(0); function generatePassword ($length = 8) { // start with a blank password $password = ""; // define possible characters - any character in this string can be // picked for use in the password, so if you want to put vowels back in // or add special characters such as exclamation marks, this is where // you should do it $possible = "2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ"; // we refer to the length of $possible a few times, so let's grab it now $maxlength = strlen($possible); // check for length overflow and truncate if necessary if ($length > $maxlength) { $length = $maxlength; } // set up a counter for how many characters are in the password so far $i = 0; // add random characters to $password until $length is reached while ($i < $length) { // pick a random character from the possible ones $char = substr($possible, mt_rand(0, $maxlength-1), 1); // have we already used this character in $password? if (!strstr($password, $char)) { // no, so it's OK to add it onto the end of whatever we've already got... $password .= $char; // ... and increase the counter by one $i++; } } // done! return $password; } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Guest WIFI Access - Add a user</title> <script> function randomPassword(length) { chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; pass = ""; for(x=0;x<length;x++) { i = Math.floor(Math.random() * 62); pass += chars.charAt(i); } return pass; } </script> </head> <body > <div id="test-header" class="accordion_headings" >Guest WIFI Network </div><!--Heading of the accordion ( clicked to show n hide ) --> <!--Prefix of heading (the DIV above this) and content (the DIV below this) to be same... eg. foo-header & foo-content--> <div id="test2-content"><!--DIV which show/hide on click of header--> <p><br /> <? if ($_REQUEST["action"]=="send") { $headers = "MIME-Version: 1.0\n" ; $headers .= "Content-Type: text/html; charset=\"iso-8859-1\"\n"; $headers .= "Sensitivity: Personal\n"; $message= "<table width=466 border=0 cellpadding=0 cellspacing=0 bordercolor=#000000> <tr> <th colspan=2> Office Guest WIFI Access</th> </tr> <tr> <td width=128>Username</td> <td width=332><strong> ".$_REQUEST[User]." </strong></td> </tr> <tr> <td>Password</td> <td><strong> ".$_REQUEST[Pass]." </strong></td> </tr> <tr> <td>Life Time</td> <td><strong> ".$_REQUEST[life]." days <br /> <font size=-2> starting from ".$_REQUEST[Date]." </font></strong> </td> </tr> </table><br> Network Name is A_GUEST<br> <b>By using Office WIFI Guest network you agree to everything listed in our policy document</b>. <br> For any IT related issues call helpdesk"; $status = mail($_REQUEST["email"], "Access to Office WIFI guest network", $message,$headers); echo "<b>Info sent by Email"; } if ($_REQUEST["action"]=="submit") { $adduser="ok"; if (strlen($_REQUEST["User"])<2) { $adduser=""; $_REQUEST["action"]=""; $userermsg.="<br><font color=red>Username too short</font>"; } if (strlen($_REQUEST["Pass"])<2) { $adduser=""; $_REQUEST["action"]=""; $userermsg.="<br><font color=red>Password too short</font>"; } if ($adduser=="ok") { // Adding user $userermsg=""; $post = http_build_query(array( "buttonClicked" => "4", "userpwd" => $_REQUEST["Pass"] , "pwdconfirm" => $_REQUEST["Pass"], "lifetime_days" => $_REQUEST["life"], "lifetime_hours" => "0", "lifetime_mins" => "1", "lifetime_secs" => "1", "apply" => "apply", "description" => "Email:".$_REQUEST["email"]." - ".$_REQUEST["notes"], "GuestWlanID" => "0", "guest_roleselect_checkbox" => "0", "err_flag" => "0", "username" => $_REQUEST["User"] )); $context = stream_context_create(array("http"=>array( "method" => "POST", "header" => "Content-Type: application/x-www-form-urlencoded\r\n" . "Content-Length: ". strlen($post) . "\r\n", "content" => $post, ))); $page = file_get_contents("http://lobbyadmin:lobbypassword@10.24.32.61/screens/aaa/guestuser_create.html", true, $context); $usererr = strpos($page, 'ERROR: User Name', true); // As of PHP 5.3.0 if (intval($usererr)>1) { $_REQUEST["action"]=""; $userermsg.="<br><font color=red>User already exists! Please choose another name</font>"; } if ($userermsg=="") { //User created - give options - printout send by email ?> <script type="text/javascript"> var win=null; function printIt(printThis) { win = window.open(); win.focus(); win.document.open(); win.document.write('<'+'html'+'><'+'head'+'><'+'style'+'>'); win.document.write('body, td { font-family: Verdana; font-size: 10pt;} table { margin: 1em; border-collapse: collapse; } td, th { padding: .3em; border: 1px #ccc solid; }'); win.document.write('<'+'/'+'style'+'><'+'/'+'head'+'><'+'body'+'>'); win.document.write(printThis); win.document.write('By using Office WIFI Guest network you agree to everything listed in our policy document. <br> For any IT related issues call (+41)(022)(909) <b>5555</b> <'+'/'+'body'+'><'+'/'+'html'+'>'); win.document.close(); win.print(); win.close(); } </script> </p> <p class="style2">User has been successfully created </p> <table width="466" border="0" cellpadding="0" cellspacing="0" bordercolor="#000000"> <tr> <th colspan="2"> Office Guest WIFI Access</th> </tr> <tr> <td width="128">Username</td> <td width="332"><strong> <?=$_REQUEST["User"]?> </strong></td> </tr> <tr> <td>Password</td> <td><strong> <?=$_REQUEST["Pass"]?> </strong></td> </tr> <tr> <td>Life Time</td> <td><strong> <?=$_REQUEST["life"]?> days <br /> <font size="-2"> starting from <?=date("d/M/YH:i:s")?> </font></strong> </td> </tr> </table> <br /> <a href="#" onclick="printIt(document.getElementById('printme').innerHTML); return false"> Print guest access leaflet </a> <? if (strlen($_REQUEST["email"])>5 ) { ?> <br /> <form action="index.php?action=send" method="post" id=sendemail> <input type=hidden name="Date" value="<?=date("d/M/YH:i:s")?>"/> <input type=hidden name="User" value="<?=$_REQUEST["User"]?>"/> <input type=hidden value="<?=$_REQUEST["Pass"]?>" id="Pass" name="Pass" /> <input type=hidden name="life" id="life" size="5" value="<? if(intval($_REQUEST["life"]==0)) { echo 1; } else { echo $_REQUEST["life"]; } ?>" /> <input type=hidden name="email" id="email" value="<?=$_REQUEST["email"]?>" /><a href=# onclick="document.getElementById('sendemail').submit(); return false;" >Send guest access leaflet by email </a> </form> <? } ?> </p> <p> <style> table { margin: 1em; border-collapse: collapse; } td, th { padding: .3em; border: 1px #ccc solid; } </style> <div id="printme" style="display:none"> <table width="466" border="0" cellpadding="0" cellspacing="0" bordercolor="#000000"> <tr> <th colspan="2"> Office Guest WIFI Access</th> </tr> <tr> <td width="128">Username</td> <td width="332"><strong> <?=$_REQUEST["User"]?> </strong></td> </tr> <tr> <td>Password</td> <td><strong> <?=$_REQUEST["Pass"]?> </strong></td> </tr> <tr> <td>Life Time</td> <td><strong> <?=$_REQUEST["life"]?> days <br /> <font size="-2" > starting from <?=date("d/M/YH:i:s")?> </font></strong></td> </tr> <tr> <td>Network Name <br /> (SSID)</td> <td><strong>A_GUEST</strong></td> </tr> <tr> <td colspan="2"><div align="center">Welcome to WiFi</div></td> </tr> </table> </div> <? } } } if ($_REQUEST["action"]=="") { if ($_REQUEST["Pass"]=="") { $_REQUEST["Pass"]=generatePassword(4); } ?> <form action="index.php" method="post" enctype="multipart/form-data"><?=$userermsg?> <table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr> <td align="right">USERNAME</td> <td align="left"><input name=User value="<?=$_REQUEST["User"]?>"/> <input name="action" type="hidden" id="action" value="submit" /></td> </tr> <tr> <td align="right">PASSWORD</td> <td align="left"><input value="<?=$_REQUEST["Pass"]?>" id=Pass name=Pass /> [<a href=# onclick="document.getElementById('Pass').value=randomPassword(4); return false;">regenerate</a>] </td> </tr> <tr> <td align="right">LIFETIME*</td> <td align="left"> <input name="life" id="life" size="5" value="<? if(intval($_REQUEST["life"]==0)) { echo 1; } else { echo $_REQUEST["life"]; } ?>" /> <a href=# style="text-decoration:none" class="links" onclick="document.getElementById('life').value=parseInt(document.getElementById('life').value)+1; return false;">[+]</a> <a style="text-decoration:none" href=# class="links" onclick="if (parseInt(document.getElementById('life').value)>1){document.getElementById('life').value=parseInt(document.getElementById('life').value)-1; }return false;">[-]</a> <a style="text-decoration:none" href=# class="links" onclick=" document.getElementById('life').value=29;return false;">[month]</a> <a style="text-decoration:none" href=# class="links" onclick=" document.getElementById('life').value=0;return false;">[0]</a> </span></td> </tr> <tr> <td align="right"> </td> <td align="left">* days</td> </tr> <tr> <td align="right"> </td> <td align="left"> <input type="submit" value=Add /> </td> </tr> <tr> <td align="right" valign="top" > </td> <td align="left"> </td> </tr> <tr> <td align="right" valign="top" ><div align="center"></div></td> <td align="right" valign="top" ><div align="left"><strong>Optional information</strong></div></td> </tr> <tr> <td align="right" valign="top"> </td> <td align="left"> </td> </tr> <tr> <td align="right" valign="middle">Email</td> <td align="left"><input name="email" id="email" value="<?=$_REQUEST["email"]?>" /> <br /></td> </tr> <tr> <td align="right" valign="middle">Additional info</td> <td align="left"><input name="notes" type="text" id="notes" value="<?=$_REQUEST["notes"]?>" size="2" /> </td> </tr> <tr> <td align="right" valign="middle"> </td> <td align="left"><a href=# onclick="document.getElementById('notes').value='staff member'; return false;">SM</a> | <a href=# onclick="document.getElementById('notes').value='natcom user'; return false;">NC</a>| <a href=# onclick="document.getElementById('notes').value='consultant'; return false;">cons</a>| <a href=# onclick="document.getElementById('notes').value='field office user'; return false;">FO</a> | <a href=# onclick="document.getElementById('notes').value='partner company'; return false;">partn</a>  </td> </tr> </table> <p align="right"> </p> <p><br /> <br /> </p> </form> <? } ?> </div> </div> <!--End of each accordion item--> <!--Start of each accordion item--> </div> </body> </html> 


The principle of operation is quite simple, PHP generates all form fields and sends a POST request to the WLC
Access to the script must be limited (for example, using htpasswd). We did this using mod_ntlm, which at the same time eliminated the need to enter a password — integrated authentification is used
You can also use curl and connect via https - in our case this is not critical, since the web server and the WLC are connected to each other through an isolated management VLAN

What happened


The result was an interface that completely arranged the reception staff.
Here is what they need to do to create a guest account:

1. Go to the address (shortcut on the desktop)
2. Immediately the user creation form opens (login is not required, the password is pregenerated)

3. Fits in the user name (here you can AJAX-ohm check whether the user exists with the login - we have not yet implemented it)
4. Basically, access is granted per day (as set by default) - you can increase the reference with the + and -, or give immediately for a month or a week

5. Shred and print

More than 10 seconds, it no longer takes!

Source: https://habr.com/ru/post/178985/


All Articles