Commit f4a09b17 by Tomas Hlavacek

Add support for router ACL.

Add support for ACL that could be associated with a router to restrict
users that are eligible to run commands on the router.

Just add acl=['username1','username2',...] to the configuration
into the parameters of the router.
parent 9268ed2e
......@@ -21,6 +21,6 @@ from ulgbird import *
routers = [
CiscoRouter(host='testrouter1.core.company.com', user='xyz', password='xyz', asn=1234),
CiscoRouter(host='testrouter2.core.company.com', user='xyz', password='xyz', asn=2345),
CiscoRouter(host='testrouter2.core.company.com', user='xyz', password='xyz', asn=2345, acl=['user1','user2']),
BirdRouterLocal('/var/run/bird.ctl', asn=3456)
]
......@@ -56,6 +56,7 @@ STRING_COMMAND='Command'
STRING_ERROR_COMMANDRUN='Error encountered while preparing or running command'
STRING_BAD_PARAMS='Verification of command or parameters failed.'
STRING_SESSION_OVERLIMIT = "<em>Limit of maximum concurrently running sessions and/or queries has been reached. The command can not be executed now. Please try again later.</em>"
STRING_SESSION_ACCESSDENIED = "<em>Access denied. The command can not be executed. Please contact the administrator.</em>"
STRING_ARBITRARY_ERROR = "Error encountered. Operation aborted. See log for further details."
STRING_IPADDRESS = "IP address"
STRING_IPSUBNET = "IP subnet"
......
......@@ -139,18 +139,20 @@
<label for="routerselect">1. Router selection:</label>
<select id="routerselect" name="routerid" onchange="updateFormCommands()">
<py:for each="ridx,rtr in enumerate(routers)">
<py:choose>
<py:when test="ridx == default_routerid">
<option value="$ridx" selected="selected">
${rtr.getName()}
</option>
</py:when>
<py:otherwise>
<option value="$ridx">
${rtr.getName()}
</option>
</py:otherwise>
</py:choose>
<py:if test="rtr.checkACL(user)">
<py:choose>
<py:when test="ridx == default_routerid">
<option value="$ridx" selected="selected">
${rtr.getName()}
</option>
</py:when>
<py:otherwise>
<option value="$ridx">
${rtr.getName()}
</option>
</py:otherwise>
</py:choose>
</py:if>
</py:for>
</select>
......
......@@ -377,13 +377,14 @@ class DecoratorHelper:
class ULGCgi:
def __init__(self):
def __init__(self,user=None):
self.loader=TemplateLoader(
os.path.join(os.path.dirname(__file__), defaults.template_dir),
auto_reload=True
)
self.decorator_helper = DecoratorHelper()
self.user = user
def print_text_html(self):
......@@ -456,6 +457,10 @@ class ULGCgi:
session.setResult(defaults.STRING_SESSION_OVERLIMIT)
session.setFinished()
def stopSessionAccessDenied(self,session):
session.setResult(defaults.STRING_SESSION_ACCESSDENIED)
session.setFinished()
def getRefreshInterval(self,datalength=None):
if(datalength):
return (datalength/(1024*100))*defaults.refresh_interval + defaults.refresh_interval
......@@ -483,7 +488,7 @@ class ULGCgi:
</body>
</html>""" % url
def runCommand(self,session):
def runCommand(self,session,user=None):
class FakeSessionFile(object):
def __init__(self,session):
self.session = session
......@@ -505,6 +510,12 @@ class ULGCgi:
session.setFinished()
decreaseUsageMethod()
# check router ACL
if user:
if not session.getRouter().checkACL(user):
self.stopSessionAccessDenied(session)
return
# try to increase usage counter
if(self.increaseUsage()):
# start new thread if needed
......@@ -534,6 +545,7 @@ class ULGCgi:
else:
# stop and report no-op
self.stopSessionOverlimit(session)
return
def renderULGIndex(self,routerid=0,commandid=0,sessionid=None):
......@@ -545,7 +557,8 @@ class ULGCgi:
default_routerid=routerid,
default_commandid=commandid,
default_sessionid=sessionid,
getFormURL=self.decorator_helper.getRuncommandURL
getFormURL=self.decorator_helper.getRuncommandURL,
user=self.user
).render('html', doctype='html', encoding='utf-8')
......@@ -638,6 +651,7 @@ class ULGCgi:
getFormURL=self.decorator_helper.getRuncommandURL,
resrange=str(session.getRange()),
resrangeb=getRangeStepURLs(session,self.decorator_helper),
user=self.user,
).render('html', doctype='html', encoding='utf-8')
def renderULGError(self,sessionid=None,**params):
......@@ -657,7 +671,8 @@ class ULGCgi:
default_sessionid=None,
result=Markup(result_text) if(result_text) else None,
refresh=0,
getFormURL=self.decorator_helper.getRuncommandURL
getFormURL=self.decorator_helper.getRuncommandURL,
user=self.user
).render('html', doctype='html', encoding='utf-8')
def renderULGDebug(self,**params):
......@@ -676,7 +691,8 @@ class ULGCgi:
default_sessionid=None,
result=Markup(result_text) if(result_text) else None,
refresh=0,
getFormURL=self.decorator_helper.getRuncommandURL()
getFormURL=self.decorator_helper.getRuncommandURL(),
user=self.user
).render('html', doctype='html', encoding='utf-8')
......@@ -752,7 +768,10 @@ class ULGCgi:
if __name__=="__main__":
try:
form = cgi.FieldStorage()
handler = ULGCgi()
user=None
if 'REMOTE_USER' in os.environ:
user=os.environ['REMOTE_USER']
handler = ULGCgi(user)
action = form.getvalue('action',None)
params = dict([(k,form.getvalue(k)) for k in form.keys() if k != 'action'])
......
......@@ -460,8 +460,8 @@ class BirdRouter(ulgmodel.Router):
class BirdRouterLocal(ulgmodel.LocalRouter,BirdRouter):
def __init__(self,sock=defaults.default_bird_sock,commands=None,proto_fltr=None,asn='My ASN',name='localhost'):
ulgmodel.LocalRouter.__init__(self)
def __init__(self,sock=defaults.default_bird_sock,commands=None,proto_fltr=None,asn='My ASN',name='localhost',acl=None):
ulgmodel.LocalRouter.__init__(self,acl=acl)
BirdRouter.__init__(self)
self.sock = sock
......@@ -577,8 +577,8 @@ class BirdRouterRemote(ulgmodel.RemoteRouter,BirdRouter):
PS_KEY_BGP = '-bgppeers'
PS_KEY_RT = '-routetab'
def __init__(self,host,user,password='',port=22,commands=None,proto_fltr=None,asn='My ASN',name=None,bin_birdc=None,bin_ssh=None):
ulgmodel.RemoteRouter.__init__(self)
def __init__(self,host,user,password='',port=22,commands=None,proto_fltr=None,asn='My ASN',name=None,bin_birdc=None,bin_ssh=None,acl=None):
ulgmodel.RemoteRouter.__init__(self,acl=acl)
BirdRouter.__init__(self)
self.setHost(host)
......@@ -615,6 +615,7 @@ class BirdRouterRemote(ulgmodel.RemoteRouter,BirdRouter):
else:
self.setCommands(self._getDefaultCommands())
def getForkNeeded(self):
return True
......
......@@ -795,7 +795,9 @@ class CiscoRouter(ulgmodel.RemoteRouter):
]
def __init__(self, host, user, password, port=22, commands=None, enable_bgp=True, asn='My ASN', name=None):
def __init__(self, host, user, password, port=22, commands=None, enable_bgp=True, asn='My ASN', name=None, acl=None):
ulgmodel.RemoteRouter.__init__(self,acl=acl)
self.setHost(host)
self.setPort(port)
self.setUser(user)
......
......@@ -415,9 +415,10 @@ class AnyCommand(TextCommand):
return c
class Router(object):
def __init__(self):
def __init__(self,acl=None):
self.setCommands([])
self.setName('')
self.acl = acl
def setName(self,name):
self.name=name
......@@ -435,6 +436,14 @@ class Router(object):
for c in self.listCommands():
c.rescanHook(self)
def checkACL(self,user):
log("Checking ACL: user="+str(user)+" acl="+str(self.acl))
if self.acl:
if not user in self.acl:
return False
return True
def returnError(self,error=None):
r = defaults.STRING_ERROR_COMMANDRUN
r = r + ': '+error if error else r
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment