Skip to content

Commit 6f53348

Browse files
committed
Merge branch 'devel'
2 parents 852798b + 3ef5654 commit 6f53348

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2893
-364
lines changed

backend/connections.py

Lines changed: 103 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,96 @@
66

77
import json
88
import os
9+
import logging
910

10-
from liberouterapi import auth
11+
from liberouterapi import socketio, auth
1112
from flask import request
13+
from eventlet.timeout import Timeout
1214
import yang
1315
import netconf2 as nc
1416

1517
from .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
1720
from .error import NetopeerException
21+
from .schemas import getschema, schemas_update
1822
from .data import *
1923

24+
log = logging.getLogger(__name__)
25+
2026
sessions = {}
2127

2228
def 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()
2797
def 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()
66148
def 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()
88170
def 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()
161243
def 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()
169251
def 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()
177259
def 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()
204286
def 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()
281363
def 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()
385467
def 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()
404486
def 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.'}))

backend/data.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import yang
1111
import netconf2 as nc
12+
from .schemas import make_schema_key
13+
1214

1315
def infoBuiltInType(base):
1416
return {
@@ -76,7 +78,7 @@ def schemaInfoNode(schema):
7678

7779
if info["type"] == yang.LYS_LEAF:
7880
schemaInfoType(schema.subtype(), info)
79-
info["key"] = False if schema.subtype().is_key() == -1 else True
81+
info["key"] = False if schema.subtype().is_key() == None else True
8082
dflt = schema.subtype().dflt()
8183
if dflt:
8284
info["default"] = dflt
@@ -149,6 +151,8 @@ def dataInfoNode(node, parent=None, recursion=False):
149151
result = {}
150152
if info["type"] == yang.LYS_LEAF or info["type"] == yang.LYS_LEAFLIST:
151153
result["value"] = casted.value_str()
154+
if info["datatypebase"] == "identityref":
155+
info["refmodule"] = make_schema_key(casted.value().ident().module())
152156
elif recursion:
153157
result["children"] = []
154158
if node.child():

backend/devices.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,22 @@ def __devices_inv_save(path, devices):
4949

5050
@auth.required()
5151
def devices_list():
52-
session = auth.lookup(request.headers.get('Authorization', None))
52+
session = auth.lookup(request.headers.get('lgui-Authorization', None))
5353
user = session['user']
5454
path = os.path.join(INVENTORY, user.username)
55-
55+
5656
inventory_check(path)
5757
devices = __devices_inv_load(path)
58-
58+
5959
for dev in devices['device']:
60-
del dev['password']
60+
if 'password' in dev:
61+
del dev['password']
62+
6163
return(json.dumps(devices['device']))
6264

6365
@auth.required()
6466
def devices_add():
65-
session = auth.lookup(request.headers.get('Authorization', None))
67+
session = auth.lookup(request.headers.get('lgui-Authorization', None))
6668
user = session['user']
6769
path = os.path.join(INVENTORY, user.username)
6870

@@ -79,11 +81,10 @@ def devices_add():
7981
'name':device['name'],
8082
'hostname':device['hostname'],
8183
'port':device['port'],
82-
'autoconnect':device['autoconnect']}
83-
if 'username' in device:
84-
device_json['username'] = device['username']
85-
if 'password' in device:
86-
device_json['password'] = device['password']
84+
'autoconnect':device['autoconnect'],
85+
'username':device['username']}
86+
if 'password' in device and device['password']:
87+
device_json['password'] = device['password']
8788
devices['device'].append(device_json)
8889

8990
#store the list
@@ -93,7 +94,7 @@ def devices_add():
9394

9495
@auth.required()
9596
def devices_rm():
96-
session = auth.lookup(request.headers.get('Authorization', None))
97+
session = auth.lookup(request.headers.get('lgui-Authorization', None))
9798
user = session['user']
9899
path = os.path.join(INVENTORY, user.username)
99100

@@ -107,7 +108,7 @@ def devices_rm():
107108
if device['id'] == rm_id:
108109
devices['device'].pop(i)
109110
device = None
110-
break;
111+
break
111112

112113
if device:
113114
# device not in inventory
@@ -128,3 +129,16 @@ def devices_get(device_id, username):
128129
return device
129130

130131
return None
132+
133+
134+
def devices_replace(device_id, username, device):
135+
path = os.path.join(INVENTORY, username)
136+
devices = __devices_inv_load(path)
137+
138+
for i in range(len(devices['device'])):
139+
if devices['device'][i]['id'] == device_id:
140+
devices['device'][i] = device
141+
break
142+
143+
# update the inventory database
144+
__devices_inv_save(path, devices)

0 commit comments

Comments
 (0)