def start_term(authname, cfm, connection, params, path, authdata, skipauth): elems = path.split('/') if len(elems) < 4 or elems[1] != 'nodes': raise exc.InvalidArgumentException('Invalid path {0}'.format(path)) node = elems[2] ccons = ClientConsole(connection) skipreplay = False if params and 'skipreplay' in params and params['skipreplay']: skipreplay = True if elems[3] == "console": consession = consoleserver.ConsoleSession(node=node, configmanager=cfm, username=authname, datacallback=ccons.sendall, skipreplay=skipreplay) elif len(elems) >= 6 and elems[3:5] == ['shell', 'sessions']: if len(elems) == 7: sessionid = elems[5] else: sessionid = None consession = shellserver.ShellSession(node=node, configmanager=cfm, username=authname, datacallback=ccons.sendall, skipreplay=skipreplay, sessionid=sessionid) else: raise exc.InvalidArgumentException('Invalid path {0}'.format(path)) if consession is None: raise Exception("TODO") term_interact(authdata, authname, ccons, cfm, connection, consession, skipauth)
def start_term(authname, cfm, connection, params, path, authdata, skipauth): elems = path.split('/') if len(elems) < 4 or elems[1] != 'nodes': raise exc.InvalidArgumentException('Invalid path {0}'.format(path)) node = elems[2] ccons = ClientConsole(connection) skipreplay = False if params and 'skipreplay' in params and params['skipreplay']: skipreplay = True if elems[3] == "console": consession = consoleserver.ConsoleSession(node=node, configmanager=cfm, username=authname, datacallback=ccons.sendall, skipreplay=skipreplay) elif len(elems) >= 6 and elems[3:5] == ['shell', 'sessions']: if len(elems) == 7: sessionid = elems[5] else: sessionid = None consession = shellserver.ShellSession(node=node, configmanager=cfm, username=authname, datacallback=ccons.sendall, skipreplay=skipreplay, sessionid=sessionid) else: raise exc.InvalidArgumentException('Invalid path {0}'.format(path)) if consession is None: raise Exception("TODO") send_data(connection, {'started': 1}) ccons.startsending() bufferage = consession.get_buffer_age() if bufferage is not False: send_data(connection, {'bufferage': bufferage}) while consession is not None: data = tlvdata.recv(connection) if type(data) == dict: if data['operation'] == 'stop': consession.destroy() return elif data['operation'] == 'break': consession.send_break() continue elif data['operation'] == 'reopen': consession.reopen() continue else: process_request(connection, data, cfm, authdata, authname, skipauth) continue if not data: consession.destroy() return consession.write(data)
def resourcehandler_backend(env, start_response): """Function to handle new wsgi requests """ mimetype, extension = _pick_mimetype(env) headers = [('Content-Type', mimetype), ('Cache-Control', 'no-store'), ('Pragma', 'no-cache'), ('X-Content-Type-Options', 'nosniff'), ('Content-Security-Policy', "default-src 'self'"), ('X-XSS-Protection', '1; mode=block'), ('X-Frame-Options', 'deny'), ('Strict-Transport-Security', 'max-age=86400'), ('X-Permitted-Cross-Domain-Policies', 'none')] reqbody = None reqtype = None if 'CONTENT_LENGTH' in env and int(env['CONTENT_LENGTH']) > 0: reqbody = env['wsgi.input'].read(int(env['CONTENT_LENGTH'])) reqtype = env['CONTENT_TYPE'] operation = opmap[env['REQUEST_METHOD']] querydict = _get_query_dict(env, reqbody, reqtype) if 'restexplorerop' in querydict: operation = querydict['restexplorerop'] del querydict['restexplorerop'] authorized = _authorize_request(env, operation) if 'logout' in authorized: start_response('200 Successful logout', headers) yield ('{"result": "200 - Successful logout"}') return if 'HTTP_SUPPRESSAUTHHEADER' in env or 'HTTP_CONFLUENTAUTHTOKEN' in env: badauth = [('Content-type', 'text/plain')] else: badauth = [('Content-type', 'text/plain'), ('WWW-Authenticate', 'Basic realm="confluent"')] if authorized['code'] == 401: start_response('401 Authentication Required', badauth) yield 'authentication required' return if authorized['code'] == 403: start_response('403 Forbidden', badauth) yield 'authorization failed' return if authorized['code'] != 200: raise Exception("Unrecognized code from auth engine") headers.extend(("Set-Cookie", m.OutputString()) for m in authorized['cookie'].values()) cfgmgr = authorized['cfgmgr'] if (operation == 'create') and env['PATH_INFO'] == '/sessions/current/async': pagecontent = "" try: for rsp in _assemble_json( confluent.asynchttp.handle_async( env, querydict, httpsessions[authorized['sessionid']]['inflight'])): pagecontent += rsp start_response("200 OK", headers) yield pagecontent return except exc.ConfluentException as e: if e.apierrorcode == 500: # raise generics to trigger the tracelog raise start_response('{0} {1}'.format(e.apierrorcode, e.apierrorstr), headers) yield e.get_error_body() elif (env['PATH_INFO'].endswith('/forward/web') and env['PATH_INFO'].startswith('/nodes/')): prefix, _, _ = env['PATH_INFO'].partition('/forward/web') _, _, nodename = prefix.rpartition('/') hm = cfgmgr.get_node_attributes(nodename, 'hardwaremanagement.manager') targip = hm.get(nodename, {}).get('hardwaremanagement.manager', {}).get('value', None) if not targip: start_response('404 Not Found', headers) yield 'No hardwaremanagemnet.manager defined for node' return funport = forwarder.get_port(targip, env['HTTP_X_FORWARDED_FOR'], authorized['sessionid']) host = env['HTTP_X_FORWARDED_HOST'] url = 'https://{0}:{1}/'.format(host, funport) start_response('302', [('Location', url)]) yield 'Our princess is in another castle!' return elif (operation == 'create' and ('/console/session' in env['PATH_INFO'] or '/shell/sessions/' in env['PATH_INFO'])): #hard bake JSON into this path, do not support other incarnations if '/console/session' in env['PATH_INFO']: prefix, _, _ = env['PATH_INFO'].partition('/console/session') shellsession = False elif '/shell/sessions/' in env['PATH_INFO']: prefix, _, _ = env['PATH_INFO'].partition('/shell/sessions') shellsession = True _, _, nodename = prefix.rpartition('/') if 'session' not in querydict.keys() or not querydict['session']: auditmsg = { 'operation': 'start', 'target': env['PATH_INFO'], 'user': authorized['username'], } if 'tenant' in authorized: auditmsg['tenant'] = authorized['tenant'] auditlog.log(auditmsg) # Request for new session skipreplay = False if 'skipreplay' in querydict and querydict['skipreplay']: skipreplay = True datacallback = None async = None if 'HTTP_CONFLUENTASYNCID' in env: async = confluent.asynchttp.get_async(env, querydict) termrel = async .set_term_relation(env) datacallback = termrel.got_data try: if shellsession: consession = shellserver.ShellSession( node=nodename, configmanager=cfgmgr, username=authorized['username'], skipreplay=skipreplay, datacallback=datacallback) else: consession = consoleserver.ConsoleSession( node=nodename, configmanager=cfgmgr, username=authorized['username'], skipreplay=skipreplay, datacallback=datacallback) except exc.NotFoundException: start_response("404 Not found", headers) yield "404 - Request Path not recognized" return if not consession: start_response("500 Internal Server Error", headers) return sessid = _assign_consessionid(consession) if async: async .add_console_session(sessid) start_response('200 OK', headers) yield '{"session":"%s","data":""}' % sessid return elif 'bytes' in querydict.keys(): # not keycodes... myinput = querydict['bytes'] sessid = querydict['session'] if sessid not in consolesessions: start_response('400 Expired Session', headers) return consolesessions[sessid]['expiry'] = time.time() + 90 consolesessions[sessid]['session'].write(myinput) start_response('200 OK', headers) yield json.dumps({'session': querydict['session']}) return # client has requests to send or receive, not both... elif 'closesession' in querydict: consolesessions[querydict['session']]['session'].destroy() del consolesessions[querydict['session']] start_response('200 OK', headers) yield '{"sessionclosed": true}' return elif 'action' in querydict: if querydict['action'] == 'break': consolesessions[querydict['session']]['session'].send_break() elif querydict['action'] == 'reopen': consolesessions[querydict['session']]['session'].reopen() else: start_response('400 Bad Request') yield 'Unrecognized action ' + querydict['action'] return start_response('200 OK', headers) yield json.dumps({'session': querydict['session']}) else: # no keys, but a session, means it's hooking to receive data sessid = querydict['session'] if sessid not in consolesessions: start_response('400 Expired Session', headers) yield '' return consolesessions[sessid]['expiry'] = time.time() + 90 # add our thread to the 'inflight' to have a hook to terminate # a long polling request loggedout = None mythreadid = greenlet.getcurrent() httpsessions[authorized['sessionid']]['inflight'].add(mythreadid) try: outdata = consolesessions[sessid]['session'].get_next_output( timeout=25) except greenlet.GreenletExit as ge: loggedout = ge httpsessions[authorized['sessionid']]['inflight'].discard( mythreadid) if sessid not in consolesessions: start_response('400 Expired Session', headers) yield '' return if loggedout is not None: consolesessions[sessid]['session'].destroy() start_response('401 Logged out', headers) yield '{"loggedout": 1}' return bufferage = False if 'stampsent' not in consolesessions[sessid]: consolesessions[sessid]['stampsent'] = True bufferage = consolesessions[sessid]['session'].get_buffer_age() if isinstance(outdata, dict): rspdata = outdata rspdata['session'] = querydict['session'] else: rspdata = {'session': querydict['session'], 'data': outdata} if bufferage is not False: rspdata['bufferage'] = bufferage try: rsp = json.dumps(rspdata) except UnicodeDecodeError: try: rsp = json.dumps(rspdata, encoding='cp437') except UnicodeDecodeError: rsp = json.dumps({ 'session': querydict['session'], 'data': 'DECODEERROR' }) start_response('200 OK', headers) yield rsp return else: # normal request url = env['PATH_INFO'] url = url.replace('.json', '') url = url.replace('.html', '') if url == '/sessions/current/info': start_response('200 OK', headers) sessinfo = {'username': authorized['username']} if 'authtoken' in authorized: sessinfo['authtoken'] = authorized['authtoken'] yield json.dumps(sessinfo) return resource = '.' + url[url.rindex('/'):] lquerydict = copy.deepcopy(querydict) try: hdlr = pluginapi.handle_path(url, operation, cfgmgr, querydict) if 'HTTP_CONFLUENTASYNCID' in env: confluent.asynchttp.run_handler(hdlr, env) start_response('202 Accepted', headers) yield 'Request queued' return pagecontent = "" if mimetype == 'text/html': for datum in _assemble_html(hdlr, resource, lquerydict, url, extension): pagecontent += datum else: for datum in _assemble_json(hdlr, resource, url, extension): pagecontent += datum start_response('200 OK', headers) yield pagecontent except exc.ConfluentException as e: if ((not isinstance(e, exc.LockedCredentials)) and e.apierrorcode == 500): # raise generics to trigger the tracelog raise start_response('{0} {1}'.format(e.apierrorcode, e.apierrorstr), headers) yield e.get_error_body()
def wsock_handler(ws): sessid = ws.wait() sessid = sessid.replace('ConfluentSessionId:', '') sessid = sessid[:-1] currsess = httpsessions.get(sessid, None) if not currsess: return authtoken = ws.wait() authtoken = authtoken.replace('ConfluentAuthToken:', '') authtoken = authtoken[:-1] if currsess['csrftoken'] != authtoken: return mythreadid = greenlet.getcurrent() httpsessions[sessid]['inflight'].add(mythreadid) name = httpsessions[sessid]['name'] authdata = auth.authorize(name, ws.path) if not authdata: return if '/console/session' in ws.path or '/shell/sessions/' in ws.path: #hard bake JSON into this path, do not support other incarnations if '/console/session' in ws.path: prefix, _, _ = ws.path.partition('/console/session') shellsession = False elif '/shell/sessions/' in ws.path: prefix, _, _ = ws.path.partition('/shell/sessions') shellsession = True _, _, nodename = prefix.rpartition('/') geom = ws.wait() geom = geom[1:] geom = json.loads(geom) width = geom['width'] height = geom['height'] skipreplay = geom.get('skipreplay', False) cfgmgr = httpsessions[sessid]['cfgmgr'] username = httpsessions[sessid]['name'] def datacallback(data): if isinstance(data, dict): data = json.dumps(data) ws.send(u'!' + data) else: try: data = data.decode('utf8') except UnicodeDecodeError: data = data.decode('cp437') ws.send(u' ' + data) try: if shellsession: consession = shellserver.ShellSession( node=nodename, configmanager=cfgmgr, username=username, skipreplay=skipreplay, datacallback=datacallback, width=width, height=height) else: consession = consoleserver.ConsoleSession( node=nodename, configmanager=cfgmgr, username=username, skipreplay=skipreplay, datacallback=datacallback, width=width, height=height) except exc.NotFoundException: return clientmsg = ws.wait() try: while clientmsg is not None: if clientmsg[0] == ' ': consession.write(clientmsg[1:]) elif clientmsg[0] == '!': cmd = json.loads(clientmsg[1:]) action = cmd.get('action', None) if action == 'break': consession.send_break() elif action == 'resize': consession.resize(width=cmd['width'], height=cmd['height']) elif clientmsg[0] == '?': ws.send(u'?') clientmsg = ws.wait() finally: consession.destroy()