66
77import json
88import os
9+ import logging
910
10- from liberouterapi import auth
11+ from liberouterapi import socketio , auth
1112from flask import request
13+ from eventlet .timeout import Timeout
1214import yang
1315import netconf2 as nc
1416
1517from .inventory import INVENTORY
16- from .devices import devices_get
18+ from .socketio import sio_emit , sio_wait , sio_clean
19+ from .devices import devices_get , devices_replace
1720from .error import NetopeerException
21+ from .schemas import getschema , schemas_update
1822from .data import *
1923
24+ log = logging .getLogger (__name__ )
25+
2026sessions = {}
2127
2228def hostkey_check (hostname , state , keytype , hexa , priv ):
23- # TODO real check
24- return True
29+ if 'fingerprint' in priv ['device' ]:
30+ # check according to the stored fingerprint from previous connection
31+ if hexa == priv ['device' ]['fingerprint' ]:
32+ return True
33+ elif state != 2 :
34+ log .error ("Incorrect host key state" )
35+ state = 2
36+
37+ # ask frontend/user for hostkey check
38+ params = {'id' : priv ['session' ]['session_id' ], 'hostname' : hostname , 'state' : state , 'keytype' : keytype , 'hexa' : hexa }
39+ sio_emit ('hostcheck' , params )
40+
41+ result = False
42+ timeout = Timeout (30 )
43+ try :
44+ # wait for response from the frontend
45+ data = sio_wait (priv ['session' ]['session_id' ])
46+ result = data ['result' ]
47+ except Timeout :
48+ # no response received within the timeout
49+ log .info ("socketio: hostcheck timeout." )
50+ except KeyError :
51+ # invalid response
52+ log .error ("socketio: invalid hostcheck_result received." )
53+ finally :
54+ # we have the response
55+ sio_clean (priv ['session' ]['session_id' ])
56+ timeout .cancel ()
57+
58+ if result :
59+ # store confirmed fingerprint for future connections
60+ priv ['device' ]['fingerprint' ] = hexa ;
61+ devices_replace (priv ['device' ]['id' ], priv ['session' ]['user' ].username , priv ['device' ])
62+
63+ return result
64+
65+
66+ def auth_common (session_id ):
67+ result = None
68+ timeout = Timeout (60 )
69+ try :
70+ # wait for response from the frontend
71+ data = sio_wait (session_id )
72+ result = data ['password' ]
73+ except Timeout :
74+ # no response received within the timeout
75+ log .info ("socketio: auth request timeout." )
76+ except KeyError :
77+ # no password
78+ log .info ("socketio: invalid credential data received." )
79+ finally :
80+ # we have the response
81+ sio_clean (session_id )
82+ timeout .cancel ()
83+
84+ return result
85+
86+
87+ def auth_password (username , hostname , priv ):
88+ sio_emit ('device_auth' , {'id' : priv , 'type' : 'Password Authentication' , 'msg' : username + '@' + hostname })
89+ return auth_common (priv )
90+
91+
92+ def auth_interactive (name , instruction , prompt , priv ):
93+ sio_emit ('device_auth' , {'id' : priv , 'type' : name , 'msg' : instruction , 'prompt' : prompt })
94+ return auth_common (priv )
2595
2696@auth .required ()
2797def connect ():
28- session = auth .lookup (request .headers .get ('Authorization' , None ))
98+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
2999 user = session ['user' ]
30100 path = os .path .join (INVENTORY , user .username )
31101
@@ -43,28 +113,40 @@ def connect():
43113 raise NetopeerException ('Unknown device to connect to request.' )
44114
45115 nc .setSearchpath (path )
116+ nc .setSchemaCallback (getschema , session )
117+
118+ if 'password' in device :
119+ ssh = nc .SSH (device ['username' ], password = device ['password' ])
120+ else :
121+ ssh = nc .SSH (device ['username' ])
122+ ssh .setAuthPasswordClb (auth_password , session ['session_id' ])
123+ ssh .setAuthInteractiveClb (auth_interactive , session ['session_id' ])
46124
47- ssh = nc .SSH (device ['username' ], password = device ['password' ])
48- ssh .setAuthHostkeyCheckClb (hostkey_check )
125+ ssh .setAuthHostkeyCheckClb (hostkey_check , {'session' : session , 'device' : device })
49126 try :
50- session = nc .Session (device ['hostname' ], device ['port' ], ssh )
127+ ncs = nc .Session (device ['hostname' ], device ['port' ], ssh )
51128 except Exception as e :
129+ nc .setSchemaCallback (None )
52130 return (json .dumps ({'success' : False , 'error-msg' : str (e )}))
131+ nc .setSchemaCallback (None )
53132
54133 if not user .username in sessions :
55134 sessions [user .username ] = {}
56135
57136 # use key (as hostname:port:session-id) to store the created NETCONF session
58- key = session .host + ":" + str (session .port ) + ":" + session .id
137+ key = ncs .host + ":" + str (ncs .port ) + ":" + ncs .id
59138 sessions [user .username ][key ] = {}
60- sessions [user .username ][key ]['session' ] = session
139+ sessions [user .username ][key ]['session' ] = ncs
140+
141+ # update inventory's list of schemas
142+ schemas_update (session )
61143
62144 return (json .dumps ({'success' : True , 'session-key' : key }))
63145
64146
65147@auth .required ()
66148def session_get_capabilities ():
67- session = auth .lookup (request .headers .get ('Authorization' , None ))
149+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
68150 user = session ['user' ]
69151 req = request .args .to_dict ()
70152
@@ -73,7 +155,7 @@ def session_get_capabilities():
73155
74156 if not user .username in sessions :
75157 sessions [user .username ] = {}
76-
158+
77159 key = req ['key' ]
78160 if not key in sessions [user .username ]:
79161 return (json .dumps ({'success' : False , 'error-msg' : 'Invalid session key.' }))
@@ -86,7 +168,7 @@ def session_get_capabilities():
86168
87169@auth .required ()
88170def session_get ():
89- session = auth .lookup (request .headers .get ('Authorization' , None ))
171+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
90172 user = session ['user' ]
91173 req = request .args .to_dict ()
92174
@@ -159,23 +241,23 @@ def _checkvalue(session, req, schema):
159241
160242@auth .required ()
161243def data_checkvalue ():
162- session = auth .lookup (request .headers .get ('Authorization' , None ))
244+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
163245 req = request .args .to_dict ()
164246
165247 return _checkvalue (session , req , False )
166248
167249
168250@auth .required ()
169251def schema_checkvalue ():
170- session = auth .lookup (request .headers .get ('Authorization' , None ))
252+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
171253 req = request .args .to_dict ()
172254
173255 return _checkvalue (session , req , True )
174256
175257
176258@auth .required ()
177259def schema_values ():
178- session = auth .lookup (request .headers .get ('Authorization' , None ))
260+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
179261 user = session ['user' ]
180262 req = request .args .to_dict ()
181263
@@ -202,7 +284,7 @@ def schema_values():
202284
203285@auth .required ()
204286def schema_info ():
205- session = auth .lookup (request .headers .get ('Authorization' , None ))
287+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
206288 user = session ['user' ]
207289 req = request .args .to_dict ()
208290
@@ -279,7 +361,7 @@ def _create_child(ctx, parent, child_def):
279361
280362@auth .required ()
281363def session_commit ():
282- session = auth .lookup (request .headers .get ('Authorization' , None ))
364+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
283365 user = session ['user' ]
284366
285367 req = request .get_json (keep_order = True )
@@ -383,7 +465,7 @@ def session_commit():
383465
384466@auth .required ()
385467def session_close ():
386- session = auth .lookup (request .headers .get ('Authorization' , None ))
468+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
387469 user = session ['user' ]
388470 req = request .args .to_dict ()
389471
@@ -402,7 +484,7 @@ def session_close():
402484
403485@auth .required ()
404486def session_alive ():
405- session = auth .lookup (request .headers .get ('Authorization' , None ))
487+ session = auth .lookup (request .headers .get ('lgui- Authorization' , None ))
406488 user = session ['user' ]
407489 req = request .args .to_dict ()
408490
@@ -411,7 +493,7 @@ def session_alive():
411493
412494 if not user .username in sessions :
413495 sessions [user .username ] = {}
414-
496+
415497 key = req ['key' ]
416498 if not key in sessions [user .username ]:
417499 return (json .dumps ({'success' : False , 'error-msg' : 'Invalid session key.' }))
0 commit comments