Created
February 9, 2011 00:42
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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