Skip to content

Instantly share code, notes, and snippets.

@salanki
Created February 9, 2011 00:42
Show Gist options
  • Save salanki/817634 to your computer and use it in GitHub Desktop.
Save salanki/817634 to your computer and use it in GitHub Desktop.
Beginning of API implementation for the Cisco NAC Appliance in Scala. Should be easily usable from Java, depends on dispatch-http.
package cisconacpoller
import scala.util.matching.Regex
trait Response
case class FailResponse(reason: String) extends Response
object NoSuchUserFailure extends FailResponse("No logged in user matches the criteria")
object InvalidCredentialsFailure extends FailResponse("Username or password is incorrect")
protected class SuccessResponse(val value: String) extends Response
protected object SuccessResponse {
def apply(value: String) = new SuccessResponse(value)
def unapply(res: SuccessResponse) = {
Some(res.value.split(',').foldLeft(Map[String, String]()) { (a, b) =>
b.split('=') match {
case Array(key, value) => a + Tuple2(key, value)
case _ => a
}
})
}
}
/**
* Response for getUserInfo
* <p>
*
* @author Peter Salanki
* @param ip IP in IPv4 format
* @param mac MAC address
* @param name Name is the username
* @param provider Provider can be the LDAP server
* @param role Role is the current role assigned to the user
* @param origRole Origrole is the original role assigned to the user
* @param vlan VLAN is the original VLAN tag
* @param newVlan NEWVLAN is the current VLAN tag
* @param os Operating system of the user's system
*/
class UserInfo(val ip: String, val mac: String, val name: String, val provider: String, val role: String, val origRole: String, val vlan: Option[Int], val newVlan: Option[Int], val os: String) extends Response {
override def toString = name + "/" + ip
}
object UserInfo {
def apply(resultMap: Map[String, String]) = {
new UserInfo(resultMap("IP"), resultMap("MAC"), resultMap("NAME"), resultMap("PROVIDER"), resultMap("ROLE"), resultMap("ORIGROLE"), resultMap.get("VLAN").map(_.toInt), resultMap.get("NEWVLAN").map(_.toInt), resultMap("OS"))
}
}
object ArgumentType extends Enumeration {
type ArgumentType = Value
val IP = Value("IP")
val MAC = Value("MAC")
val NAME = Value("Name")
val ALL = Value("All")
}
/**
* Cisco NAC Appliance API
*
* @author Peter Salanki <[email protected]>
*/
class CiscoNacAppliance(server: String, username: String, password: String) {
import dispatch._
import Http._
private val http = new Http() { /* Disable logging in dispatch http this way */
override lazy val log = {
new Logger {
def info(msg: String, items: Any*) {}
}
}
}
/**
* Lookup logged in user information
* <p>
* @param arg The IP Address, MAC Address or Name to query for
* @param argType The type of the supplied argument
*
* @return UserInfo object on success, or FailResponse on error
*/
def getUserInfo(arg: String, argumentType: ArgumentType.Value): Response = {
val qtype = argumentType match {
case ArgumentType.IP => "ip"
case ArgumentType.MAC => "mac"
case ArgumentType.NAME => "name"
case other => throw new IllegalArgumentException(other.toString)
}
request("getuserinfo", Map("qtype" -> qtype, "qval" -> arg)) match {
case SuccessResponse(resultMap) => UserInfo(resultMap)
case FailResponse(reason) if reason == "No logged in user matches the criteria" => return NoSuchUserFailure
case other => other
}
}
/**
* Lookup logged in user information by IP
* <p>
* @param ip The IP Address to query for
*
* @return UserInfo object on success, or FailResponse on error
*/
def getUserInfo(ip: java.net.InetAddress): Response = getUserInfo(ip.getHostAddress, ArgumentType.IP)
/** Low level request interface */
def request(op: String, params: Map[String, String]): Response = {
val param = "admin/cisco_api.jsp?admin=" + username + "&passwd=" + password + "&op=" + op + params.foldLeft("")((a, b) => a + "&" + b._1 + "=" + b._2)
val request = :/(server) / param secure
val response = http(request.POST as_str)
val errorRegex = new Regex("<!--error=(.*)-->\r\n")
val successRegex = new Regex("<!--error=0-->\r\n<!--count=\\d*-->\r\n<!--(.*)-->\r\n")
response match {
case errorRegex(error) => error match {
case "Invalid Credentials" => InvalidCredentialsFailure
case other => FailResponse(other)
}
case successRegex(data) => SuccessResponse(data)
case other => throw new RuntimeException("Data parse failed: " + other)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment