def bootstrap(self): """ Configure and create web app """ self.log.always("\n ====== Starting DIRAC web app ====== \n") #Load required CFG files self.__loadWebAppCFGFiles() #Debug mode? devMode = Conf.devMode() if devMode: self.log.info("Configuring in developer mode...") #Calculating routes result = self.__handlerMgr.getRoutes() if not result['OK']: return result routes = result['Value'] #Initialize the session data SessionData.setHandlers(self.__handlerMgr.getHandlers()['Value']) #Create the app tLoader = TemplateLoader(self.__handlerMgr.getPaths("template")) kw = dict(devMode=devMode, template_loader=tLoader, cookie_secret=Conf.cookieSecret(), log_function=self._logRequest) #Check processes if we're under a load balancert if Conf.balancer() and Conf.numProcesses() not in (0, 1): tornado.process.fork_processes(Conf.numProcesses(), max_restarts=0) kw['devMode'] = False #Configure tornado app self.__app = tornado.web.Application(routes, **kw) self.log.notice("Configuring HTTP on port %s" % (Conf.HTTPPort())) #Create the web servers srv = tornado.httpserver.HTTPServer(self.__app) port = Conf.HTTPPort() srv.listen(port) self.__servers[('http', port)] = srv if Conf.HTTPS(): self.log.notice("Configuring HTTPS on port %s" % Conf.HTTPSPort()) sslops = dict(certfile=Conf.HTTPSCert(), keyfile=Conf.HTTPSKey(), cert_reqs=ssl.CERT_OPTIONAL, ca_certs=Conf.generateCAFile()) self.log.debug( " - %s" % "\n - ".join(["%s = %s" % (k, sslops[k]) for k in sslops])) srv = tornado.httpserver.HTTPServer(self.__app, ssl_options=sslops) port = Conf.HTTPSPort() srv.listen(port) self.__servers[('https', port)] = srv return result
def __init__(self, *args, **kwargs): """ Initialize the handler """ super(WebHandler, self).__init__(*args, **kwargs) if not WebHandler.__log: WebHandler.__log = gLogger.getSubLogger(self.__class__.__name__) self.__credDict = {} self.__setup = Conf.setup() self.__processCredentials() self.__disetConfig.reset() self.__disetConfig.setDecorator(self.__disetBlockDecor) self.__disetDump = self.__disetConfig.dump() match = self.PATH_RE.match(self.request.path) self._pathResult = self.__checkPath(*match.groups()) self.__sessionData = SessionData(self.__credDict, self.__setup)
def web_index(self): # Render base template data = SessionData().getData() self.render("root.tpl", base_url=data["baseURL"], _dev=Conf.devMode(), ext_version=data['extVersion'])
def __init__(self): self.__extVersion = SessionData.getExtJSVersion() self.__staticPaths = HandlerMgr().getPaths("static") self.__extensions = getInstalledExtensions() self.__webAppPath = os.path.dirname(self.__staticPaths[-1]) self.__extPath = os.path.join(self.__webAppPath, "static", "extjs", self.__extVersion) self.__sdkPath = os.path.join(self.__webAppPath, "static", "extjs", self.__extVersion, "src") self.__appDependency = CompilerHelper().getAppDependencies() self.__classPaths = [ os.path.join(self.__webAppPath, *p) for p in (("static", "core", "js", "utils"), ("static", "core", "js", "core")) ] self.__classPaths.append( os.path.join(self.__extPath, "examples", "ux", "form")) self.__debugFlag = str(gLogger.getLevel() in ('DEBUG', 'VERBOSE', 'INFO')).lower() self.__inDir = os.path.join(os.path.dirname(self.__webAppPath), "Lib", "CompileTemplates") self.__senchacmddir = os.path.join(rootPath, "sbin", "Sencha", "Cmd") self.__senchaVersion = "v6.5.0.180"
def __getUniqueKeyValues( self, typeName ): sessionData = SessionData().getData() userGroup = sessionData["user"]["group"] if 'NormalUser' in CS.getPropertiesForGroup( userGroup ): cacheKey = ( sessionData["user"]["username"], userGroup, sessionData["setup"], typeName ) else: cacheKey = ( userGroup, sessionData["setup"], typeName ) data = AccountingPlotOldHandler.__keysCache.get( cacheKey ) if not data: rpcClient = RPCClient( "Accounting/ReportGenerator" ) retVal = rpcClient.listUniqueKeyValues( typeName ) if 'rpcStub' in retVal: del( retVal[ 'rpcStub' ] ) if not retVal[ 'OK' ]: return retVal #Site ordering based on TierLevel / alpha if 'Site' in retVal[ 'Value' ]: siteLevel = {} for siteName in retVal[ 'Value' ][ 'Site' ]: sitePrefix = siteName.split( "." )[0].strip() level = gConfig.getValue( "/Resources/Sites/%s/%s/MoUTierLevel" % ( sitePrefix, siteName ), 10 ) if level not in siteLevel: siteLevel[ level ] = [] siteLevel[ level ].append( siteName ) orderedSites = [] for level in sorted( siteLevel ): orderedSites.extend( sorted( siteLevel[ level ] ) ) retVal[ 'Value' ][ 'Site' ] = orderedSites data = retVal AccountingPlotOldHandler.__keysCache.add( cacheKey, 300, data ) return data
def bootstrap( self ): """ Configure and create web app """ self.log.always( "\n ====== Starting DIRAC web app ====== \n" ) #Load required CFG files self.__loadWebAppCFGFiles() #Debug mode? devMode = Conf.devMode() if devMode: self.log.info( "Configuring in developer mode..." ) #Calculating routes result = self.__handlerMgr.getRoutes() if not result[ 'OK' ]: return result routes = result[ 'Value' ] #Initialize the session data SessionData.setHandlers( self.__handlerMgr.getHandlers()[ 'Value' ] ) #Create the app tLoader = TemplateLoader( self.__handlerMgr.getPaths( "template" ) ) kw = dict( devMode = devMode, template_loader = tLoader, cookie_secret = Conf.cookieSecret(), log_function = self._logRequest ) #Check processes if we're under a load balancert if Conf.balancer() and Conf.numProcesses() not in ( 0, 1 ): tornado.process.fork_processes( Conf.numProcesses(), max_restarts=0 ) kw[ 'devMode' ] = False #Configure tornado app self.__app = tornado.web.Application( routes, **kw ) self.log.notice( "Configuring HTTP on port %s" % ( Conf.HTTPPort() ) ) #Create the web servers srv = tornado.httpserver.HTTPServer( self.__app ) port = Conf.HTTPPort() srv.listen( port ) self.__servers[ ( 'http', port ) ] = srv if Conf.HTTPS(): self.log.notice( "Configuring HTTPS on port %s" % Conf.HTTPSPort() ) sslops = dict( certfile = Conf.HTTPSCert(), keyfile = Conf.HTTPSKey(), cert_reqs = ssl.CERT_OPTIONAL, ca_certs = Conf.generateCAFile() ) self.log.debug( " - %s" % "\n - ".join( [ "%s = %s" % ( k, sslops[k] ) for k in sslops ] ) ) srv = tornado.httpserver.HTTPServer( self.__app, ssl_options = sslops ) port = Conf.HTTPSPort() srv.listen( port ) self.__servers[ ( 'https', port ) ] = srv return result
def __init__( self ): self.__extVersion = SessionData.getExtJSVersion() self.__staticPaths = HandlerMgr().getPaths( "static" ) self.__extensions = getInstalledExtensions() self.__webAppPath = os.path.dirname( self.__staticPaths[-1] ) self.__extPath = os.path.join( self.__webAppPath, "static", "extjs", self.__extVersion ) self.__sdkPath = os.path.join( self.__webAppPath, "static", "extjs", self.__extVersion, "src" ) self.__classPaths = [ os.path.join( self.__webAppPath, *p ) for p in ( ("static", "core", "js", "utils" ), ("static", "core", "js", "core" ))] self.__classPaths.append( os.path.join( self.__extPath, "examples", "ux", "form" ) ) self.__debugFlag = str( gLogger.getLevel() in ( 'DEBUG', 'VERBOSE', 'INFO' ) ).lower() self.__inDir = os.path.join( os.path.dirname( self.__webAppPath ), "Lib", "CompileTemplates" )
def __init__( self, *args, **kwargs ): """ Initialize the handler """ super( WebHandler, self ).__init__( *args, **kwargs ) if not WebHandler.__log: WebHandler.__log = gLogger.getSubLogger( self.__class__.__name__ ) self.__credDict = {} self.__setup = Conf.setup() self.__processCredentials() self.__disetConfig.reset() self.__disetConfig.setDecorator( self.__disetBlockDecor ) self.__disetDump = self.__disetConfig.dump() match = self.PATH_RE.match( self.request.path ) self._pathResult = self.__checkPath( *match.groups() ) self.__sessionData = SessionData( self.__credDict, self.__setup )
def web_getConfigData(self): self.write(json.dumps(SessionData().getData()))
def __request(self): self.pageNumber = 0 self.numberOfJobs = 25 self.globalSort = [["JobID", "DESC"]] sData = SessionData().getData() req = {} group = sData["user"]["group"] user = sData["user"]["username"] if self.request.arguments.has_key("limit") and len( self.request.arguments["limit"][0]) > 0: self.numberOfJobs = int(self.request.arguments["limit"][0]) if self.request.arguments.has_key("start") and len( self.request.arguments["start"][0]) > 0: self.pageNumber = int(self.request.arguments["start"][0]) else: self.pageNumber = 0 if self.request.arguments.has_key("ids") and len( self.request.arguments["ids"][0]) > 0: req["JobID"] = [] reqIds = str(self.request.arguments["ids"][0]).split(',') for i in reqIds: testI = i.split('-') if len(testI) == 2: rangeID = range(int(testI[0].strip(' ')), int(testI[1].strip(' ')) + 1) req["JobID"].extend(rangeID) else: req["JobID"].append(i) #groupProperty = credentials.getProperties(group) result = gConfig.getOption("/Website/ListSeparator") if result["OK"]: separator = result["Value"] else: separator = "," if self.request.arguments.has_key("prod") and len( self.request.arguments["prod"][0]) > 0: if str(self.request.arguments["prod"][0]) != "": req["JobGroup"] = str( self.request.arguments["prod"][0]).split(separator) if self.request.arguments.has_key("site") and len( self.request.arguments["site"][0]) > 0: if str(self.request.arguments["site"][0]) != "": req["Site"] = [ x.strip() for x in str(self.request.arguments["site"] [0]).split(separator) ] if self.request.arguments.has_key("status") and len( self.request.arguments["status"][0]) > 0: if str(self.request.arguments["status"][0]) != "": req["Status"] = str( self.request.arguments["status"][0]).split(separator) if self.request.arguments.has_key("minorstat") and len( self.request.arguments["minorstat"][0]) > 0: if str(self.request.arguments["minorstat"][0]) != "": req["MinorStatus"] = str( self.request.arguments["minorstat"][0]).split(separator) if self.request.arguments.has_key("app") and len( self.request.arguments["app"][0]) > 0: if str(self.request.arguments["app"][0]) != "": req["ApplicationStatus"] = str( self.request.arguments["app"][0]).split(separator) if self.request.arguments.has_key("types") and len( self.request.arguments["types"][0]) > 0: if str(self.request.arguments["types"][0]) != "": req["JobType"] = str( self.request.arguments["types"][0]).split(separator) if self.request.arguments.has_key("owner") and len( self.request.arguments["owner"][0]) > 0: if str(self.request.arguments["owner"][0]) != "": req["Owner"] = str( self.request.arguments["owner"][0]).split(separator) if self.request.arguments.has_key("startDate") and len( self.request.arguments["startDate"][0]) > 0: if str(self.request.arguments["startDate"][0]) != "YYYY-mm-dd": if self.request.arguments.has_key("startTime") and len( self.request.arguments["startTime"][0]) > 0: req["FromDate"] = str( self.request.arguments["startDate"][0] + " " + self.request.arguments["startTime"][0]) else: req["FromDate"] = str( self.request.arguments["startDate"][0]) if self.request.arguments.has_key("endDate") and len( self.request.arguments["endDate"][0]) > 0: if str(self.request.arguments["endDate"][0]) != "YYYY-mm-dd": if self.request.arguments.has_key("endTime") and len( self.request.arguments["endTime"][0]) > 0: req["ToDate"] = str(self.request.arguments["endDate"][0] + " " + self.request.arguments["endTime"][0]) else: req["ToDate"] = str(self.request.arguments["endDate"][0]) if self.request.arguments.has_key("date") and len( self.request.arguments["date"][0]) > 0: if str(self.request.arguments["date"][0]) != "YYYY-mm-dd": req["LastUpdate"] = str(self.request.arguments["date"][0]) if self.request.arguments.has_key("sort") and len( self.request.arguments["sort"][0]) > 0: sortValue = self.request.arguments["sort"][0] #converting the string into a dictionary sortValue = ast.literal_eval(sortValue.strip("[]")) self.globalSort = [[sortValue["property"], sortValue["direction"]]] return req
def web_standalone(self): self.render("JobMonitor/standalone.tpl", config_data=json.dumps(SessionData().getData()))
class WebHandler(tornado.web.RequestHandler): __disetConfig = ThreadConfig() __log = False # Auth requirements AUTH_PROPS = None # Location of the handler in the URL LOCATION = "" # URL Schema with holders to generate handler urls URLSCHEMA = "" # RE to extract group and setup PATH_RE = "" def threadTask(self, method, *args, **kwargs): if tornado.version < '5.0.0': return self.threadTaskOld(method, *args, **kwargs) else: return self.threadTaskExecutor(method, *args, **kwargs) # Helper function to create threaded gen.Tasks with automatic callback and execption handling @deprecated("Only for Tornado 4.x.x and DIRAC v6r20") def threadTaskOld(self, method, *args, **kwargs): """ Helper method to generate a gen.Task and automatically call the callback when the real method ends. THIS IS SPARTAAAAAAAAAA. SPARTA has improved using futures ;) """ # Save the task to access the runner genTask = False # This runs in the separate thread, calls the callback on finish and takes into account exceptions def cbMethod(*cargs, **ckwargs): cb = ckwargs.pop('callback') method = cargs[0] disetConf = cargs[1] cargs = cargs[2] self.__disetConfig.reset() self.__disetConfig.load(disetConf) ioloop = tornado.ioloop.IOLoop.instance() try: result = method(*cargs, **ckwargs) ioloop.add_callback(functools.partial(cb, result)) except Exception as excp: gLogger.error("Following exception occured %s" % excp) exc_info = sys.exc_info() genTask.set_exc_info(exc_info) ioloop.add_callback(lambda: genTask.exception()) # Put the task in the thread :) def threadJob(tmethod, *targs, **tkwargs): tkwargs['callback'] = tornado.stack_context.wrap(tkwargs['callback']) targs = (tmethod, self.__disetDump, targs) gThreadPool.submit(cbMethod, *targs, **tkwargs) # Return a YieldPoint genTask = tornado.gen.Task(threadJob, method, *args, **kwargs) return genTask def threadTaskExecutor(self, method, *args, **kwargs): def threadJob(*targs, **tkwargs): args = targs[0] disetConf = targs[1] self.__disetConfig.reset() self.__disetConfig.load(disetConf) return method(*args, **tkwargs) targs = (args, self.__disetDump) return tornado.ioloop.IOLoop.current().run_in_executor(gThreadPool, functools.partial(threadJob, *targs, **kwargs)) def __disetBlockDecor(self, func): def wrapper(*args, **kwargs): raise RuntimeError("All DISET calls must be made from inside a Threaded Task!") return wrapper def __init__(self, *args, **kwargs): """ Initialize the handler """ super(WebHandler, self).__init__(*args, **kwargs) if not WebHandler.__log: WebHandler.__log = gLogger.getSubLogger(self.__class__.__name__) self.__credDict = {} self.__setup = Conf.setup() self.__processCredentials() self.__disetConfig.reset() self.__disetConfig.setDecorator(self.__disetBlockDecor) self.__disetDump = self.__disetConfig.dump() match = self.PATH_RE.match(self.request.path) self._pathResult = self.__checkPath(*match.groups()) self.__sessionData = SessionData(self.__credDict, self.__setup) def __processCredentials(self): """ Extract the user credentials based on the certificate or what comes from the balancer """ if not self.request.protocol == "https": return # OIDC auth method def oAuth2(): if self.get_secure_cookie("AccessToken"): access_token = self.get_secure_cookie("AccessToken") url = Conf.getCSValue("TypeAuths/%s/authority" % typeAuth) + '/userinfo' heads = {'Authorization': 'Bearer ' + access_token, 'Content-Type': 'application/json'} if 'error' in requests.get(url, headers=heads, verify=False).json(): self.log.error('OIDC request error: %s' % requests.get(url, headers=heads, verify=False).json()['error']) return ID = requests.get(url, headers=heads, verify=False).json()['sub'] result = getUsernameForID(ID) if result['OK']: self.__credDict['username'] = result['Value'] result = getDNForUsername(self.__credDict['username']) if result['OK']: self.__credDict['validDN'] = True self.__credDict['DN'] = result['Value'][0] result = getCAForUsername(self.__credDict['username']) if result['OK']: self.__credDict['issuer'] = result['Value'][0] return # Type of Auth if not self.get_secure_cookie("TypeAuth"): self.set_secure_cookie("TypeAuth", 'Certificate') typeAuth = self.get_secure_cookie("TypeAuth") self.log.info("Type authentication: %s" % str(typeAuth)) if typeAuth == "Visitor": return retVal = Conf.getCSSections("TypeAuths") if retVal['OK']: if typeAuth in retVal.get("Value"): method = Conf.getCSValue("TypeAuths/%s/method" % typeAuth, 'default') if method == "oAuth2": oAuth2() # NGINX if Conf.balancer() == "nginx": headers = self.request.headers if headers['X-Scheme'] == "https" and headers['X-Ssl_client_verify'] == 'SUCCESS': DN = headers['X-Ssl_client_s_dn'] if not DN.startswith('/'): items = DN.split(',') items.reverse() DN = '/' + '/'.join(items) self.__credDict['DN'] = DN self.__credDict['issuer'] = headers['X-Ssl_client_i_dn'] result = Registry.getUsernameForDN(DN) if not result['OK']: self.__credDict['validDN'] = False else: self.__credDict['validDN'] = True self.__credDict['username'] = result['Value'] return # TORNADO derCert = self.request.get_ssl_certificate(binary_form=True) if not derCert: return pemCert = ssl.DER_cert_to_PEM_cert(derCert) chain = X509Chain() chain.loadChainFromString(pemCert) result = chain.getCredentials() if not result['OK']: self.log.error("Could not get client credentials %s" % result['Message']) return self.__credDict = result['Value'] # Hack. Data coming from OSSL directly and DISET difer in DN/subject try: self.__credDict['DN'] = self.__credDict['subject'] except KeyError: pass def _request_summary(self): """ Return a string returning the summary of the request """ summ = super(WebHandler, self)._request_summary() cl = [] if self.__credDict.get('validDN', False): cl.append(self.__credDict['username']) if self.__credDict.get('validGroup', False): cl.append("@%s" % self.__credDict['group']) cl.append(" (%s)" % self.__credDict['DN']) summ = "%s %s" % (summ, "".join(cl)) return summ @property def log(self): return self.__log @classmethod def getLog(cls): return cls.__log def getUserDN(self): return self.__credDict.get('DN', '') def getUserName(self): return self.__credDict.get('username', '') def getUserGroup(self): return self.__credDict.get('group', '') def getUserSetup(self): return self.__setup def getUserProperties(self): return self.__sessionData.getData().properties def isRegisteredUser(self): return self.__credDict.get('validDN', "") and self.__credDict.get('validGroup', "") def getSessionData(self): return self.__sessionData.getData() def actionURL(self, action=""): """ Given an action name for the handler, return the URL """ if action == "index": action = "" group = self.getUserGroup() if group: group = "/g:%s" % group setup = self.getUserSetup() if setup: setup = "/s:%s" % setup location = self.LOCATION if location: location = "/%s" % location ats = dict(action=action, group=group, setup=setup, location=location) return self.URLSCHEMA % ats def __auth(self, handlerRoute, group, method): """ Authenticate request :param str handlerRoute: the name of the handler :param str group: DIRAC group :param str method: the name of the method :return: bool """ userDN = self.getUserDN() if group: self.__credDict['group'] = group else: if userDN: result = Registry.findDefaultGroupForDN(userDN) if result['OK']: self.__credDict['group'] = result['Value'] self.__credDict['validGroup'] = False if type(self.AUTH_PROPS) not in (types.ListType, types.TupleType): self.AUTH_PROPS = [p.strip() for p in self.AUTH_PROPS.split(",") if p.strip()] auth = AuthManager(Conf.getAuthSectionForHandler(handlerRoute)) ok = auth.authQuery(method, self.__credDict, self.AUTH_PROPS) if ok: if userDN: self.__credDict['validGroup'] = True self.log.info("AUTH OK: %s by %s@%s (%s)" % (handlerRoute, self.__credDict['username'], self.__credDict['group'], userDN)) else: self.__credDict['validDN'] = False self.log.info("AUTH OK: %s by visitor" % (handlerRoute)) elif self.isTrustedHost(self.__credDict.get('DN')): self.log.info("Request is coming from Trusted host") return True else: self.log.info("AUTH KO: %s by %s@%s" % (handlerRoute, userDN, group)) return ok def isTrustedHost(self, dn): """ Check if the request coming from a TrustedHost :param str dn: certificate DN :return: bool if the host is Trusrted it return true otherwise false """ retVal = CS.getHostnameForDN(dn) if retVal['OK']: hostname = retVal['Value'] if Properties.TRUSTED_HOST in CS.getPropertiesForHost(hostname, []): return True return False def __checkPath(self, setup, group, route): """ Check the request, auth, credentials and DISET config """ if route[-1] == "/": methodName = "index" handlerRoute = route else: iP = route.rfind("/") methodName = route[iP + 1:] handlerRoute = route[:iP] if setup: self.__setup = setup if not self.__auth(handlerRoute, group, methodName): return WErr(401, "Unauthorized.") DN = self.getUserDN() if DN: self.__disetConfig.setDN(DN) group = self.getUserGroup() if group: self.__disetConfig.setGroup(group) self.__disetConfig.setSetup(setup) self.__disetDump = self.__disetConfig.dump() return WOK(methodName) def get(self, setup, group, route): if not self._pathResult.ok: raise self._pathResult methodName = "web_%s" % self._pathResult.data try: mObj = getattr(self, methodName) except AttributeError as e: self.log.fatal("This should not happen!! %s" % e) raise tornado.web.HTTPError(404) return mObj() def post(self, *args, **kwargs): return self.get(*args, **kwargs) def write_error(self, status_code, **kwargs): self.set_status(status_code) cType = "text/plain" data = self._reason if 'exc_info' in kwargs: ex = kwargs['exc_info'][1] trace = traceback.format_exception(*kwargs["exc_info"]) if not isinstance(ex, WErr): data += "\n".join(trace) else: if self.settings.get("debug"): self.log.error("Request ended in error:\n %s" % "\n ".join(trace)) data = ex.msg if isinstance(data, dict): cType = "application/json" data = json.dumps(data) self.set_header('Content-Type', cType) self.finish(data)
def bootstrap(self): """ Configure and create web app """ self.log.always("\n ====== Starting DIRAC web app ====== \n") # Load required CFG files if not self._loadDefaultWebCFG( ): # if we have a web.cfg under etc directory we use it, otherwise we use the configuration file defined by the developer self._loadWebAppCFGFiles() # Calculating routes result = self.__handlerMgr.getRoutes() if not result['OK']: return result routes = result['Value'] # Initialize the session data SessionData.setHandlers(self.__handlerMgr.getHandlers()['Value']) # Create the app tLoader = TemplateLoader(self.__handlerMgr.getPaths("template")) kw = dict(debug=Conf.devMode(), template_loader=tLoader, cookie_secret=Conf.cookieSecret(), log_function=self._logRequest, autoreload=Conf.numProcesses() < 2) #please do no move this lines. The lines must be before the fork_processes signal.signal(signal.SIGTERM, self.stopChildProcesses) signal.signal(signal.SIGINT, self.stopChildProcesses) # Check processes if we're under a load balancert if Conf.balancer() and Conf.numProcesses() not in (0, 1): tornado.process.fork_processes(Conf.numProcesses(), max_restarts=0) kw['debug'] = False # Debug mode? if kw['debug']: self.log.info("Configuring in developer mode...") # Configure tornado app self.__app = tornado.web.Application(routes, **kw) self.log.notice("Configuring HTTP on port %s" % (Conf.HTTPPort())) # Create the web servers srv = tornado.httpserver.HTTPServer(self.__app, xheaders=True) port = Conf.HTTPPort() srv.listen(port) self.__servers[('http', port)] = srv Conf.generateRevokedCertsFile() # it is used by nginx.... if Conf.HTTPS(): self.log.notice("Configuring HTTPS on port %s" % Conf.HTTPSPort()) sslops = dict(certfile=Conf.HTTPSCert(), keyfile=Conf.HTTPSKey(), cert_reqs=ssl.CERT_OPTIONAL, ca_certs=Conf.generateCAFile(), ssl_version=ssl.PROTOCOL_TLSv1) sslprotocol = str(Conf.SSLProrocol()) aviableProtocols = [i for i in dir(ssl) if i.find('PROTOCOL') == 0] if sslprotocol and sslprotocol != "": if (sslprotocol in aviableProtocols): sslops['ssl_version'] = getattr(ssl, sslprotocol) else: message = "%s protocol is not provided. The following protocols are provided: %s" % ( sslprotocol, str(aviableProtocols)) gLogger.warn(message) self.log.debug( " - %s" % "\n - ".join(["%s = %s" % (k, sslops[k]) for k in sslops])) srv = tornado.httpserver.HTTPServer(self.__app, ssl_options=sslops, xheaders=True) port = Conf.HTTPSPort() srv.listen(port) self.__servers[('https', port)] = srv else: #when NGINX is used then the Conf.HTTPS return False, it means tornado does not have to be configured using 443 port Conf.generateCAFile( ) # if we use Nginx we have to generate the cas as well... return result
class WebHandler(tornado.web.RequestHandler): __disetConfig = ThreadConfig() __log = False # Auth requirements AUTH_PROPS = None # Location of the handler in the URL LOCATION = "" # URL Schema with holders to generate handler urls URLSCHEMA = "" # RE to extract group and setup PATH_RE = "" def threadTask(self, method, *args, **kwargs): if tornado.version < '5.0.0': return self.threadTaskOld(method, *args, **kwargs) else: return self.threadTaskExecutor(method, *args, **kwargs) # Helper function to create threaded gen.Tasks with automatic callback and execption handling @deprecated("Only for Tornado 4.x.x and DIRAC v6r20") def threadTaskOld(self, method, *args, **kwargs): """ Helper method to generate a gen.Task and automatically call the callback when the real method ends. THIS IS SPARTAAAAAAAAAA. SPARTA has improved using futures ;) """ # Save the task to access the runner genTask = False # This runs in the separate thread, calls the callback on finish and takes into account exceptions def cbMethod(*cargs, **ckwargs): cb = ckwargs.pop('callback') method = cargs[0] disetConf = cargs[1] cargs = cargs[2] self.__disetConfig.reset() self.__disetConfig.load(disetConf) ioloop = tornado.ioloop.IOLoop.instance() try: result = method(*cargs, **ckwargs) ioloop.add_callback(functools.partial(cb, result)) except Exception as excp: gLogger.error("Following exception occured %s" % excp) exc_info = sys.exc_info() genTask.set_exc_info(exc_info) ioloop.add_callback(lambda: genTask.exception()) # Put the task in the thread :) def threadJob(tmethod, *targs, **tkwargs): tkwargs['callback'] = tornado.stack_context.wrap( tkwargs['callback']) targs = (tmethod, self.__disetDump, targs) gThreadPool.submit(cbMethod, *targs, **tkwargs) # Return a YieldPoint genTask = tornado.gen.Task(threadJob, method, *args, **kwargs) return genTask def threadTaskExecutor(self, method, *args, **kwargs): def threadJob(*targs, **tkwargs): args = targs[0] disetConf = targs[1] self.__disetConfig.reset() self.__disetConfig.load(disetConf) return method(*args, **tkwargs) targs = (args, self.__disetDump) return tornado.ioloop.IOLoop.current().run_in_executor( gThreadPool, functools.partial(threadJob, *targs, **kwargs)) def __disetBlockDecor(self, func): def wrapper(*args, **kwargs): raise RuntimeError( "All DISET calls must be made from inside a Threaded Task!") return wrapper def __init__(self, *args, **kwargs): """ Initialize the handler """ super(WebHandler, self).__init__(*args, **kwargs) if not WebHandler.__log: WebHandler.__log = gLogger.getSubLogger(self.__class__.__name__) self.__credDict = {} self.__setup = Conf.setup() self.__processCredentials() self.__disetConfig.reset() self.__disetConfig.setDecorator(self.__disetBlockDecor) self.__disetDump = self.__disetConfig.dump() match = self.PATH_RE.match(self.request.path) self._pathResult = self.__checkPath(*match.groups()) self.__sessionData = SessionData(self.__credDict, self.__setup) def __processCredentials(self): """ Extract the user credentials based on the certificate or what comes from the balancer """ if not self.request.protocol == "https": return # OIDC auth method def oAuth2(): if self.get_secure_cookie("AccessToken"): access_token = self.get_secure_cookie("AccessToken") url = Conf.getCSValue( "TypeAuths/%s/authority" % typeAuth) + '/userinfo' heads = { 'Authorization': 'Bearer ' + access_token, 'Content-Type': 'application/json' } if 'error' in requests.get(url, headers=heads, verify=False).json(): self.log.error('OIDC request error: %s' % requests.get( url, headers=heads, verify=False).json()['error']) return ID = requests.get(url, headers=heads, verify=False).json()['sub'] result = getUsernameForID(ID) if result['OK']: self.__credDict['username'] = result['Value'] result = getDNForUsername(self.__credDict['username']) if result['OK']: self.__credDict['validDN'] = True self.__credDict['DN'] = result['Value'][0] result = getCAForUsername(self.__credDict['username']) if result['OK']: self.__credDict['issuer'] = result['Value'][0] return # Type of Auth if not self.get_secure_cookie("TypeAuth"): self.set_secure_cookie("TypeAuth", 'Certificate') typeAuth = self.get_secure_cookie("TypeAuth") self.log.info("Type authentication: %s" % str(typeAuth)) if typeAuth == "Visitor": return retVal = Conf.getCSSections("TypeAuths") if retVal['OK']: if typeAuth in retVal.get("Value"): method = Conf.getCSValue("TypeAuths/%s/method" % typeAuth, 'default') if method == "oAuth2": oAuth2() # NGINX if Conf.balancer() == "nginx": headers = self.request.headers if headers['X-Scheme'] == "https" and headers[ 'X-Ssl_client_verify'] == 'SUCCESS': DN = headers['X-Ssl_client_s_dn'] if not DN.startswith('/'): items = DN.split(',') items.reverse() DN = '/' + '/'.join(items) self.__credDict['DN'] = DN self.__credDict['issuer'] = headers['X-Ssl_client_i_dn'] result = Registry.getUsernameForDN(DN) if not result['OK']: self.__credDict['validDN'] = False else: self.__credDict['validDN'] = True self.__credDict['username'] = result['Value'] return # TORNADO derCert = self.request.get_ssl_certificate(binary_form=True) if not derCert: return pemCert = ssl.DER_cert_to_PEM_cert(derCert) chain = X509Chain() chain.loadChainFromString(pemCert) result = chain.getCredentials() if not result['OK']: self.log.error("Could not get client credentials %s" % result['Message']) return self.__credDict = result['Value'] # Hack. Data coming from OSSL directly and DISET difer in DN/subject try: self.__credDict['DN'] = self.__credDict['subject'] except KeyError: pass def _request_summary(self): """ Return a string returning the summary of the request """ summ = super(WebHandler, self)._request_summary() cl = [] if self.__credDict.get('validDN', False): cl.append(self.__credDict['username']) if self.__credDict.get('validGroup', False): cl.append("@%s" % self.__credDict['group']) cl.append(" (%s)" % self.__credDict['DN']) summ = "%s %s" % (summ, "".join(cl)) return summ @property def log(self): return self.__log @classmethod def getLog(cls): return cls.__log def getUserDN(self): return self.__credDict.get('DN', '') def getUserName(self): return self.__credDict.get('username', '') def getUserGroup(self): return self.__credDict.get('group', '') def getUserSetup(self): return self.__setup def getUserProperties(self): return self.__sessionData.getData().properties def isRegisteredUser(self): return self.__credDict.get('validDN', "") and self.__credDict.get( 'validGroup', "") def getSessionData(self): return self.__sessionData.getData() def actionURL(self, action=""): """ Given an action name for the handler, return the URL """ if action == "index": action = "" group = self.getUserGroup() if group: group = "/g:%s" % group setup = self.getUserSetup() if setup: setup = "/s:%s" % setup location = self.LOCATION if location: location = "/%s" % location ats = dict(action=action, group=group, setup=setup, location=location) return self.URLSCHEMA % ats def __auth(self, handlerRoute, group, method): """ Authenticate request :param str handlerRoute: the name of the handler :param str group: DIRAC group :param str method: the name of the method :return: bool """ userDN = self.getUserDN() if group: self.__credDict['group'] = group else: if userDN: result = Registry.findDefaultGroupForDN(userDN) if result['OK']: self.__credDict['group'] = result['Value'] self.__credDict['validGroup'] = False if type(self.AUTH_PROPS) not in (types.ListType, types.TupleType): self.AUTH_PROPS = [ p.strip() for p in self.AUTH_PROPS.split(",") if p.strip() ] auth = AuthManager(Conf.getAuthSectionForHandler(handlerRoute)) ok = auth.authQuery(method, self.__credDict, self.AUTH_PROPS) if ok: if userDN: self.__credDict['validGroup'] = True self.log.info("AUTH OK: %s by %s@%s (%s)" % (handlerRoute, self.__credDict['username'], self.__credDict['group'], userDN)) else: self.__credDict['validDN'] = False self.log.info("AUTH OK: %s by visitor" % (handlerRoute)) elif self.isTrustedHost(self.__credDict.get('DN')): self.log.info("Request is coming from Trusted host") return True else: self.log.info("AUTH KO: %s by %s@%s" % (handlerRoute, userDN, group)) return ok def isTrustedHost(self, dn): """ Check if the request coming from a TrustedHost :param str dn: certificate DN :return: bool if the host is Trusrted it return true otherwise false """ retVal = CS.getHostnameForDN(dn) if retVal['OK']: hostname = retVal['Value'] if Properties.TRUSTED_HOST in CS.getPropertiesForHost( hostname, []): return True return False def __checkPath(self, setup, group, route): """ Check the request, auth, credentials and DISET config """ if route[-1] == "/": methodName = "index" handlerRoute = route else: iP = route.rfind("/") methodName = route[iP + 1:] handlerRoute = route[:iP] if setup: self.__setup = setup if not self.__auth(handlerRoute, group, methodName): return WErr(401, "Unauthorized.") DN = self.getUserDN() if DN: self.__disetConfig.setDN(DN) group = self.getUserGroup() if group: self.__disetConfig.setGroup(group) self.__disetConfig.setSetup(setup) self.__disetDump = self.__disetConfig.dump() return WOK(methodName) def get(self, setup, group, route): if not self._pathResult.ok: raise self._pathResult methodName = "web_%s" % self._pathResult.data try: mObj = getattr(self, methodName) except AttributeError as e: self.log.fatal("This should not happen!! %s" % e) raise tornado.web.HTTPError(404) return mObj() def post(self, *args, **kwargs): return self.get(*args, **kwargs) def write_error(self, status_code, **kwargs): self.set_status(status_code) cType = "text/plain" data = self._reason if 'exc_info' in kwargs: ex = kwargs['exc_info'][1] trace = traceback.format_exception(*kwargs["exc_info"]) if not isinstance(ex, WErr): data += "\n".join(trace) else: if self.settings.get("debug"): self.log.error("Request ended in error:\n %s" % "\n ".join(trace)) data = ex.msg if isinstance(data, dict): cType = "application/json" data = json.dumps(data) self.set_header('Content-Type', cType) self.finish(data)
class WebHandler( tornado.web.RequestHandler ): __disetConfig = ThreadConfig() __log = False #Auth requirements AUTH_PROPS = None #Location of the handler in the URL LOCATION = "" #URL Schema with holders to generate handler urls URLSCHEMA = "" #RE to extract group and setup PATH_RE = "" #Helper function to create threaded gen.Tasks with automatic callback and execption handling def threadTask( self, method, *args, **kwargs ): """ Helper method to generate a gen.Task and automatically call the callback when the real method ends. THIS IS SPARTAAAAAAAAAA. SPARTA has improved using futures ;) """ #Save the task to access the runner genTask = False #This runs in the separate thread, calls the callback on finish and takes into account exceptions def cbMethod( *cargs, **ckwargs ): cb = ckwargs.pop( 'callback' ) method = cargs[0] disetConf = cargs[1] cargs = cargs[2] self.__disetConfig.reset() self.__disetConfig.load( disetConf ) ioloop = tornado.ioloop.IOLoop.instance() try: result = method( *cargs, **ckwargs ) ioloop.add_callback( functools.partial( cb, result ) ) except Exception as excp: gLogger.error( "Following exception occured %s" % excp ) exc_info = sys.exc_info() genTask.set_exc_info( exc_info ) ioloop.add_callback( lambda : genTask.exception() ) #Put the task in the thread :) def threadJob( tmethod, *targs, **tkwargs ): tkwargs[ 'callback' ] = tornado.stack_context.wrap( tkwargs[ 'callback' ] ) targs = ( tmethod, self.__disetDump, targs ) gThreadPool.submit( cbMethod, *targs, **tkwargs ) #Return a YieldPoint genTask = tornado.gen.Task( threadJob, method, *args, **kwargs ) return genTask def __disetBlockDecor( self, func ): def wrapper( *args, **kwargs ): raise RuntimeError( "All DISET calls must be made from inside a Threaded Task! Bad boy!" ) return wrapper def __init__( self, *args, **kwargs ): """ Initialize the handler """ super( WebHandler, self ).__init__( *args, **kwargs ) if not WebHandler.__log: WebHandler.__log = gLogger.getSubLogger( self.__class__.__name__ ) self.__credDict = {} self.__setup = Conf.setup() self.__processCredentials() self.__disetConfig.reset() self.__disetConfig.setDecorator( self.__disetBlockDecor ) self.__disetDump = self.__disetConfig.dump() match = self.PATH_RE.match( self.request.path ) self._pathResult = self.__checkPath( *match.groups() ) self.__sessionData = SessionData( self.__credDict, self.__setup ) def __processCredentials( self ): """ Extract the user credentials based on the certificate or what comes from the balancer """ #NGINX if Conf.balancer() == "nginx": headers = self.request.headers if headers[ 'X-Scheme' ] == "https" and headers[ 'X-Ssl_client_verify' ] == 'SUCCESS': DN = headers[ 'X-Ssl_client_s_dn' ] self.__credDict[ 'DN' ] = DN self.__credDict[ 'issuer' ] = headers[ 'X-Ssl_client_i_dn' ] result = Registry.getUsernameForDN( DN ) if not result[ 'OK' ]: self.__credDict[ 'validDN' ] = False else: self.__credDict[ 'validDN' ] = True self.__credDict[ 'username' ] = result[ 'Value' ] return #TORNADO if not self.request.protocol == "https": return derCert = self.request.get_ssl_certificate( binary_form = True ) if not derCert: return pemCert = ssl.DER_cert_to_PEM_cert( derCert ) chain = X509Chain() chain.loadChainFromString( pemCert ) result = chain.getCredentials() if not result[ 'OK' ]: self.log.error( "Could not get client credentials %s" % result[ 'Message' ] ) return self.__credDict = result[ 'Value' ] #Hack. Data coming from OSSL directly and DISET difer in DN/subject try: self.__credDict[ 'DN' ] = self.__credDict[ 'subject' ] except KeyError: pass def _request_summary( self ): """ Return a string returning the summary of the request """ summ = super( WebHandler, self )._request_summary() cl = [] if self.__credDict.get( 'validDN', False ): cl.append( self.__credDict[ 'username' ] ) if self.__credDict.get( 'validGroup', False ): cl.append( "@%s" % self.__credDict[ 'group' ] ) cl.append( " (%s)" % self.__credDict[ 'DN' ] ) summ = "%s %s" % ( summ, "".join( cl ) ) return summ @property def log( self ): return self.__log @classmethod def getLog( cls ): return cls.__log def getUserDN( self ): return self.__credDict.get( 'DN', '' ) def getUserName( self ): return self.__credDict.get( 'username', '' ) def getUserGroup( self ): return self.__credDict.get( 'group', '' ) def getUserSetup( self ): return self.__setup def getUserProperties( self ): return self.__sessionData.getData().properties def isRegisteredUser( self ): return self.__credDict.get( 'validDN', "" ) and self.__credDict.get( 'validGroup', "" ) def getSessionData( self ): return self.__sessionData.getData() def actionURL( self, action = "" ): """ Given an action name for the handler, return the URL """ if action == "index": action = "" group = self.getUserGroup() if group: group = "/g:%s" % group setup = self.getUserSetup() if setup: setup = "/s:%s" % setup location = self.LOCATION if location: location = "/%s" % location ats = dict( action = action, group = group, setup = setup, location = location ) return self.URLSCHEMA % ats def __auth( self, handlerRoute, group ): """ Authenticate request """ userDN = self.getUserDN() if group: self.__credDict[ 'group' ] = group else: if userDN: result = Registry.findDefaultGroupForDN( userDN ) if result[ 'OK' ]: self.__credDict[ 'group' ] = result[ 'Value' ] self.__credDict[ 'validGroup' ] = False if type( self.AUTH_PROPS ) not in ( types.ListType, types.TupleType ): self.AUTH_PROPS = [ p.strip() for p in self.AUTH_PROPS.split( "," ) if p.strip() ] allAllowed = False for p in self.AUTH_PROPS: if p.lower() in ( 'all', 'any' ): allAllowed = True auth = AuthManager( Conf.getAuthSectionForHandler( handlerRoute ) ) ok = auth.authQuery( "", self.__credDict, self.AUTH_PROPS ) if ok: if userDN: self.__credDict[ 'validGroup' ] = True self.log.info( "AUTH OK: %s by %s@%s (%s)" % ( handlerRoute, self.__credDict[ 'username' ], self.__credDict[ 'group' ], userDN ) ) else: self.__credDict[ 'validDN' ] = False self.log.info( "AUTH OK: %s by visitor" % ( handlerRoute ) ) elif allAllowed: self.log.info( "AUTH ALL: %s by %s" % ( handlerRoute, userDN ) ) ok = True else: self.log.info( "AUTH KO: %s by %s@%s" % ( handlerRoute, userDN, group ) ) return ok def __checkPath( self, setup, group, route ): """ Check the request, auth, credentials and DISET config """ if route[-1] == "/": methodName = "index" handlerRoute = route else: iP = route.rfind( "/" ) methodName = route[ iP + 1: ] handlerRoute = route[ :iP ] if setup: self.__setup = setup if not self.__auth( handlerRoute, group ): return WErr( 401, "Unauthorized, bad boy!" ) DN = self.getUserDN() if DN: self.__disetConfig.setDN( DN ) group = self.getUserGroup() if group: self.__disetConfig.setGroup( group ) self.__disetConfig.setSetup( setup ) self.__disetDump = self.__disetConfig.dump() return WOK( methodName ) def get( self, setup, group, route ): if not self._pathResult.ok: raise self._pathResult methodName = "web_%s" % self._pathResult.data try: mObj = getattr( self, methodName ) except AttributeError as e: self.log.fatal( "This should not happen!! %s" % e ) raise tornado.web.HTTPError( 404 ) return mObj() def post( self, *args, **kwargs ): return self.get( *args, **kwargs ) def write_error( self, status_code, **kwargs ): self.set_status( status_code ) cType = "text/plain" data = self._reason if 'exc_info' in kwargs: ex = kwargs[ 'exc_info' ][1] trace = traceback.format_exception( *kwargs["exc_info"] ) if not isinstance( ex, WErr ): data += "\n".join( trace ) else: if self.settings.get("debug"): self.log.error( "Request ended in error:\n %s" % "\n ".join( trace ) ) data = ex.msg if type( data ) == types.DictType: cType = "application/json" data = json.dumps( data ) self.set_header( 'Content-Type', cType ) self.finish( data )
class WebHandler(tornado.web.RequestHandler): __disetConfig = ThreadConfig() __log = False #Auth requirements AUTH_PROPS = None #Location of the handler in the URL LOCATION = "" #URL Schema with holders to generate handler urls URLSCHEMA = "" #RE to extract group and setup PATH_RE = "" #Helper function to create threaded gen.Tasks with automatic callback and execption handling def threadTask(self, method, *args, **kwargs): """ Helper method to generate a gen.Task and automatically call the callback when the real method ends. THIS IS SPARTAAAAAAAAAA. SPARTA has improved using futures ;) """ #Save the task to access the runner genTask = False #This runs in the separate thread, calls the callback on finish and takes into account exceptions def cbMethod(*cargs, **ckwargs): cb = ckwargs.pop('callback') method = cargs[0] disetConf = cargs[1] cargs = cargs[2] self.__disetConfig.reset() self.__disetConfig.load(disetConf) ioloop = tornado.ioloop.IOLoop.instance() try: result = method(*cargs, **ckwargs) ioloop.add_callback(functools.partial(cb, result)) except Exception as excp: gLogger.error("Following exception occured %s" % excp) exc_info = sys.exc_info() genTask.set_exc_info(exc_info) ioloop.add_callback(lambda: genTask.exception()) #Put the task in the thread :) def threadJob(tmethod, *targs, **tkwargs): tkwargs['callback'] = tornado.stack_context.wrap( tkwargs['callback']) targs = (tmethod, self.__disetDump, targs) gThreadPool.submit(cbMethod, *targs, **tkwargs) #Return a YieldPoint genTask = tornado.gen.Task(threadJob, method, *args, **kwargs) return genTask def __disetBlockDecor(self, func): def wrapper(*args, **kwargs): raise RuntimeError( "All DISET calls must be made from inside a Threaded Task! Bad boy!" ) return wrapper def __init__(self, *args, **kwargs): """ Initialize the handler """ super(WebHandler, self).__init__(*args, **kwargs) if not WebHandler.__log: WebHandler.__log = gLogger.getSubLogger(self.__class__.__name__) self.__credDict = {} self.__setup = Conf.setup() self.__processCredentials() self.__disetConfig.reset() self.__disetConfig.setDecorator(self.__disetBlockDecor) self.__disetDump = self.__disetConfig.dump() match = self.PATH_RE.match(self.request.path) self._pathResult = self.__checkPath(*match.groups()) self.__sessionData = SessionData(self.__credDict, self.__setup) def __processCredentials(self): """ Extract the user credentials based on the certificate or what comes from the balancer """ #NGINX if Conf.balancer() == "nginx": headers = self.request.headers if headers['X-Scheme'] == "https" and headers[ 'X-Ssl_client_verify'] == 'SUCCESS': DN = headers['X-Ssl_client_s_dn'] self.__credDict['DN'] = DN self.__credDict['issuer'] = headers['X-Ssl_client_i_dn'] result = Registry.getUsernameForDN(DN) if not result['OK']: self.__credDict['validDN'] = False else: self.__credDict['validDN'] = True self.__credDict['username'] = result['Value'] return #TORNADO if not self.request.protocol == "https": return derCert = self.request.get_ssl_certificate(binary_form=True) if not derCert: return pemCert = ssl.DER_cert_to_PEM_cert(derCert) chain = X509Chain() chain.loadChainFromString(pemCert) result = chain.getCredentials() if not result['OK']: self.log.error("Could not get client credentials %s" % result['Message']) return self.__credDict = result['Value'] #Hack. Data coming from OSSL directly and DISET difer in DN/subject try: self.__credDict['DN'] = self.__credDict['subject'] except KeyError: pass def _request_summary(self): """ Return a string returning the summary of the request """ summ = super(WebHandler, self)._request_summary() cl = [] if self.__credDict.get('validDN', False): cl.append(self.__credDict['username']) if self.__credDict.get('validGroup', False): cl.append("@%s" % self.__credDict['group']) cl.append(" (%s)" % self.__credDict['DN']) summ = "%s %s" % (summ, "".join(cl)) return summ @property def log(self): return self.__log @classmethod def getLog(cls): return cls.__log def getUserDN(self): return self.__credDict.get('DN', '') def getUserName(self): return self.__credDict.get('username', '') def getUserGroup(self): return self.__credDict.get('group', '') def getUserSetup(self): return self.__setup def getUserProperties(self): return self.__sessionData.getData().properties def isRegisteredUser(self): return self.__credDict.get('validDN', "") and self.__credDict.get( 'validGroup', "") def getSessionData(self): return self.__sessionData.getData() def actionURL(self, action=""): """ Given an action name for the handler, return the URL """ if action == "index": action = "" group = self.getUserGroup() if group: group = "/g:%s" % group setup = self.getUserSetup() if setup: setup = "/s:%s" % setup location = self.LOCATION if location: location = "/%s" % location ats = dict(action=action, group=group, setup=setup, location=location) return self.URLSCHEMA % ats def __auth(self, handlerRoute, group): """ Authenticate request """ userDN = self.getUserDN() if group: self.__credDict['group'] = group else: if userDN: result = Registry.findDefaultGroupForDN(userDN) if result['OK']: self.__credDict['group'] = result['Value'] self.__credDict['validGroup'] = False if type(self.AUTH_PROPS) not in (types.ListType, types.TupleType): self.AUTH_PROPS = [ p.strip() for p in self.AUTH_PROPS.split(",") if p.strip() ] allAllowed = False for p in self.AUTH_PROPS: if p.lower() in ('all', 'any'): allAllowed = True auth = AuthManager(Conf.getAuthSectionForHandler(handlerRoute)) ok = auth.authQuery("", self.__credDict, self.AUTH_PROPS) if ok: if userDN: self.__credDict['validGroup'] = True self.log.info("AUTH OK: %s by %s@%s (%s)" % (handlerRoute, self.__credDict['username'], self.__credDict['group'], userDN)) else: self.__credDict['validDN'] = False self.log.info("AUTH OK: %s by visitor" % (handlerRoute)) elif allAllowed: self.log.info("AUTH ALL: %s by %s" % (handlerRoute, userDN)) ok = True else: self.log.info("AUTH KO: %s by %s@%s" % (handlerRoute, userDN, group)) return ok def __checkPath(self, setup, group, route): """ Check the request, auth, credentials and DISET config """ if route[-1] == "/": methodName = "index" handlerRoute = route else: iP = route.rfind("/") methodName = route[iP + 1:] handlerRoute = route[:iP] if setup: self.__setup = setup if not self.__auth(handlerRoute, group): return WErr(401, "Unauthorized, bad boy!") DN = self.getUserDN() if DN: self.__disetConfig.setDN(DN) group = self.getUserGroup() if group: self.__disetConfig.setGroup(group) self.__disetConfig.setSetup(setup) self.__disetDump = self.__disetConfig.dump() return WOK(methodName) def get(self, setup, group, route): if not self._pathResult.ok: raise self._pathResult methodName = "web_%s" % self._pathResult.data try: mObj = getattr(self, methodName) except AttributeError as e: self.log.fatal("This should not happen!! %s" % e) raise tornado.web.HTTPError(404) return mObj() def post(self, *args, **kwargs): return self.get(*args, **kwargs) def write_error(self, status_code, **kwargs): self.set_status(status_code) cType = "text/plain" data = self._reason if 'exc_info' in kwargs: ex = kwargs['exc_info'][1] trace = traceback.format_exception(*kwargs["exc_info"]) if not isinstance(ex, WErr): data += "\n".join(trace) else: if self.settings.get("debug"): self.log.error("Request ended in error:\n %s" % "\n ".join(trace)) data = ex.msg if type(data) == types.DictType: cType = "application/json" data = json.dumps(data) self.set_header('Content-Type', cType) self.finish(data)
def web_getSelectionData(self): sData = SessionData().getData() callback = {} group = sData["user"]["group"] user = sData["user"]["username"] ''' if len(self.request.arguments) > 0: tmp = {} for i in self.request.arguments: tmp[i] = str(self.request.arguments[i]) callback["extra"] = tmp if callback["extra"].has_key("prod"): callback["extra"]["prod"] = callback["extra"]["prod"].zfill(8) if callback["extra"]["prod"] == "00000000": callback["extra"]["prod"] = "" ''' if user == "Anonymous": callback["prod"] = [["Insufficient rights"]] else: #RPC = getRPCClient("WorkloadManagement/JobMonitoring") RPC = RPCClient("WorkloadManagement/JobMonitoring") result = RPC.getProductionIds() if result["OK"]: prod = [] prods = result["Value"] if len(prods) > 0: #prod.append([str("All")]) tmp = [] for keys in prods: try: id = str(int(keys)).zfill(8) except: id = str(keys) tmp.append(str(id)) tmp.sort(reverse=True) for i in tmp: prod.append([str(i)]) else: prod = [["Nothing to display"]] else: # gLogger.error("RPC.getProductionIds() return error: %s" % result["Message"]) prod = [["Error happened on service side"]] callback["prod"] = prod ### #RPC = getRPCClient("WorkloadManagement/JobMonitoring") RPC = RPCClient("WorkloadManagement/JobMonitoring") result = RPC.getSites() if result["OK"]: #tier1 = gConfig.getValue("/Website/PreferredSites",[]) # Always return a list site = [] if len(result["Value"]) > 0: s = list(result["Value"]) #site.append([str("All")]) for i in s: site.append([str(i)]) else: site = [["Nothing to display"]] else: gLogger.error("RPC.getSites() return error: %s" % result["Message"]) site = [["Error happened on service side"]] callback["site"] = site ### result = RPC.getStates() if result["OK"]: stat = [] if len(result["Value"]) > 0: #stat.append([str("All")]) for i in result["Value"]: stat.append([str(i)]) else: stat = [["Nothing to display"]] else: gLogger.error("RPC.getStates() return error: %s" % result["Message"]) stat = [["Error happened on service side"]] callback["status"] = stat ### result = RPC.getMinorStates() if result["OK"]: stat = [] if len(result["Value"]) > 0: #stat.append([str("All")]) for i in result["Value"]: i = i.replace(",", ";") stat.append([i]) else: stat = [["Nothing to display"]] else: gLogger.error("RPC.getMinorStates() return error: %s" % result["Message"]) stat = [["Error happened on service side"]] callback["minorstat"] = stat ### result = RPC.getApplicationStates() if result["OK"]: app = [] if len(result["Value"]) > 0: #app.append([str("All")]) for i in result["Value"]: i = i.replace(",", ";") app.append([i]) else: app = [["Nothing to display"]] else: # gLogger.error("RPC.getApplicationstates() return error: %s" % result["Message"]) app = [["Error happened on service side"]] callback["app"] = app ### result = RPC.getJobTypes() if result["OK"]: types = [] if len(result["Value"]) > 0: #types.append([str("All")]) for i in result["Value"]: i = i.replace(",", ";") types.append([i]) else: types = [["Nothing to display"]] else: # gLogger.error("RPC.getJobTypes() return error: %s" % result["Message"]) types = [["Error happened on service side"]] callback["types"] = types ### #groupProperty = credentials.getProperties(group) if user == "Anonymous": callback["owner"] = [["Insufficient rights"]] else: result = RPC.getOwners() if result["OK"]: owner = [] if len(result["Value"]) > 0: #owner.append([str("All")]) for i in result["Value"]: owner.append([str(i)]) else: owner = [["Nothing to display"]] else: # gLogger.error("RPC.getOwners() return error: %s" % result["Message"]) owner = [["Error happened on service side"]] callback["owner"] = owner self.write(json.dumps(callback))
def bootstrap( self ): """ Configure and create web app """ self.log.always( "\n ====== Starting DIRAC web app ====== \n" ) # Load required CFG files if not self._loadDefaultWebCFG(): # if we have a web.cfg under etc directory we use it, otherwise we use the configuration file defined by the developer self._loadWebAppCFGFiles() # Calculating routes result = self.__handlerMgr.getRoutes() if not result[ 'OK' ]: return result routes = result[ 'Value' ] # Initialize the session data SessionData.setHandlers( self.__handlerMgr.getHandlers()[ 'Value' ] ) # Create the app tLoader = TemplateLoader( self.__handlerMgr.getPaths( "template" ) ) kw = dict( debug = Conf.devMode(), template_loader = tLoader, cookie_secret = Conf.cookieSecret(), log_function = self._logRequest, autoreload = Conf.numProcesses() < 2 ) #please do no move this lines. The lines must be before the fork_processes signal.signal(signal.SIGTERM, self.stopChildProcesses) signal.signal(signal.SIGINT, self.stopChildProcesses) # Check processes if we're under a load balancert if Conf.balancer() and Conf.numProcesses() not in ( 0, 1 ): tornado.process.fork_processes( Conf.numProcesses(), max_restarts = 0 ) kw[ 'debug' ] = False # Debug mode? if kw[ 'debug' ]: self.log.info( "Configuring in developer mode..." ) # Configure tornado app self.__app = tornado.web.Application( routes, **kw ) self.log.notice( "Configuring HTTP on port %s" % ( Conf.HTTPPort() ) ) # Create the web servers srv = tornado.httpserver.HTTPServer( self.__app, xheaders = True ) port = Conf.HTTPPort() srv.listen( port ) self.__servers[ ( 'http', port ) ] = srv Conf.generateRevokedCertsFile() # it is used by nginx.... if Conf.HTTPS(): self.log.notice( "Configuring HTTPS on port %s" % Conf.HTTPSPort() ) sslops = dict( certfile = Conf.HTTPSCert(), keyfile = Conf.HTTPSKey(), cert_reqs = ssl.CERT_OPTIONAL, ca_certs = Conf.generateCAFile(), ssl_version = ssl.PROTOCOL_TLSv1 ) sslprotocol = str( Conf.SSLProrocol() ) aviableProtocols = [ i for i in dir( ssl ) if i.find( 'PROTOCOL' ) == 0] if sslprotocol and sslprotocol != "": if ( sslprotocol in aviableProtocols ): sslops['ssl_version'] = getattr( ssl, sslprotocol ) else: message = "%s protocol is not provided. The following protocols are provided: %s" % ( sslprotocol, str( aviableProtocols ) ) gLogger.warn( message ) self.log.debug( " - %s" % "\n - ".join( [ "%s = %s" % ( k, sslops[k] ) for k in sslops ] ) ) srv = tornado.httpserver.HTTPServer( self.__app, ssl_options = sslops, xheaders = True ) port = Conf.HTTPSPort() srv.listen( port ) self.__servers[ ( 'https', port ) ] = srv else: #when NGINX is used then the Conf.HTTPS return False, it means tornado does not have to be configured using 443 port Conf.generateCAFile() # if we use Nginx we have to generate the cas as well... return result