예제 #1
0
    def __init__(self, _arg=None, **kwd):
        if _arg is None:
            config = dict()
        elif type(_arg) is dict or type(_arg) is Configuration:
            config = dict(_arg)
        elif type(_arg) is file:
            config = json.loads(_arg.read())
            unicode2str(config)
        elif type(_arg) is str:
            with open(_arg) as source:
                config = json.loads(source.read())
                unicode2str(config)

        config.update(kwd)

        for key, value in config.iteritems():
            self[key] = parse_config(value)
예제 #2
0
    def __init__(self, _arg = None, **kwd):
        if _arg is None:
            config = dict()
        elif type(_arg) is dict or type(_arg) is Configuration:
            config = dict(_arg)
        elif type(_arg) is file:
            config = json.loads(_arg.read())
            unicode2str(config)
        elif type(_arg) is str:
            with open(_arg) as source:
                config = json.loads(source.read())
                unicode2str(config)

        config.update(kwd)

        for key, value in config.iteritems():
            self[key] = parse_config(value)
예제 #3
0
    def _request_one(self, request, timeout):
        """
        Use urllib2 opener mechanism to make on HTTP(S) request.
        """

        if self.auth_handler:
            opener = urllib2.build_opener(
                self.auth_handler(self.auth_handler_conf))
        else:
            opener = urllib2.build_opener()

        if 'Accept' not in self.headers:
            opener.addheaders.append(('Accept', self.accept))

        opener.addheaders.extend(self.headers)

        if timeout > 0:
            watcher = RequestWatcher('Webservice (%s)' %
                                     request.get_full_url())
            watcher.start(timeout)

        response = opener.open(request)

        if timeout > 0:
            watcher.stop()

        # clean up - break reference cycle so python can free the memory up
        for handler in opener.handlers:
            handler.parent = None
        del opener

        content = response.read()
        del response

        if self.accept == 'application/json':
            result = json.loads(content)
            unicode2str(result)

        elif self.accept == 'application/xml':
            # TODO implement xml -> dict
            result = content

        del content

        return result
예제 #4
0
    def __init__(self, config=dict()):
        if type(config) is file:
            config = json.loads(config.read())
            unicode2str(config)
        elif type(config) is str:
            with open(config) as source:
                config = json.loads(source.read())
                unicode2str(config)

        for key, value in config.iteritems():
            if type(value) is str:
                matches = re.findall('\$\(([^\)]+)\)', value)
                for match in matches:
                    value = value.replace('$(%s)' % match, os.environ[match])

            if type(value) is dict or type(value) is Configuration:
                self[key] = Configuration(value)
            else:
                self[key] = value
예제 #5
0
    def _request_one(self, request, timeout):
        """
        Use urllib2 opener mechanism to make on HTTP(S) request.
        """

        if self.auth_handler:
            opener = urllib2.build_opener(self.auth_handler(self.auth_handler_conf))
        else:
            opener = urllib2.build_opener()

        if 'Accept' not in self.headers:
            opener.addheaders.append(('Accept', self.accept))

        opener.addheaders.extend(self.headers)

        if timeout > 0:
            watcher = RequestWatcher('Webservice (%s)' % request.get_full_url())
            watcher.start(timeout)

        response = opener.open(request)

        if timeout > 0:
            watcher.stop()

        # clean up - break reference cycle so python can free the memory up
        for handler in opener.handlers:
            handler.parent = None
        del opener

        content = response.read()
        del response

        if self.accept == 'application/json':
            result = json.loads(content)
            unicode2str(result)

        elif self.accept == 'application/xml':
            # TODO implement xml -> dict
            result = content

        del content

        return result
예제 #6
0
파일: server.py 프로젝트: cpausmit/dynamo
    def _main(self, environ):
        """
        Body of the WSGI callable. Steps:
        1. Determine protocol. If HTTPS, identify the user.
        2. If js or css is requested, respond.
        3. Find the module class and instantiate it.
        4. Parse the query string into a dictionary.
        5. Call the run() function of the module class.
        6. Respond.
        """

        authorizer = None

        ## Step 1
        if environ['REQUEST_SCHEME'] == 'http':
            # No auth
            user, dn, user_id = None, None, 0
            authlist = []

        elif environ['REQUEST_SCHEME'] == 'https':
            authorizer = self.dynamo_server.manager.master.create_authorizer()

            # Client DN must match a known user
            try:
                dn = WebServer.format_dn(environ['SSL_CLIENT_S_DN'])
                userinfo = authorizer.identify_user(dn=dn, check_trunc=True)
                if userinfo is None:
                    raise exceptions.AuthorizationError()

                user, user_id, dn = userinfo

            except exceptions.AuthorizationError:
                self.code = 403
                self.message = 'Unknown user. Client name: %s' % environ[
                    'SSL_CLIENT_S_DN']
                return
            except:
                return self._internal_server_error()

            authlist = authorizer.list_user_auth(user)

        else:
            self.code = 400
            self.message = 'Only HTTP or HTTPS requests are allowed.'
            return

        ## Step 2
        mode = environ['SCRIPT_NAME'].strip('/')

        if mode == 'js' or mode == 'css':
            try:
                source = open(HTMLMixin.contents_path + '/' + mode +
                              environ['PATH_INFO'])
            except IOError:
                self.code = 404
                self.content_type = 'text/plain'
                return 'Invalid request %s%s.\n' % (mode, environ['PATH_INFO'])
            else:
                if mode == 'js':
                    self.content_type = 'text/javascript'
                else:
                    self.content_type = 'text/css'

                content = source.read() + '\n'
                source.close()

                return content

        ## Step 3
        if mode != 'data' and mode != 'web' and mode != 'registry' and mode != 'phedexdata':  # registry and phedexdata for backward compatibility
            self.code = 404
            self.message = 'Invalid request %s.' % mode
            return

        if mode == 'phedexdata':
            mode = 'data'
            self.phedex_request = environ['PATH_INFO'][1:]

        module, _, command = environ['PATH_INFO'][1:].partition('/')

        try:
            cls = modules[mode][module][command]
        except KeyError:
            # Was a new module added perhaps?
            load_modules()
            try:  # again
                cls = modules[mode][module][command]
            except KeyError:
                self.code = 404
                self.message = 'Invalid request %s/%s.' % (module, command)
                return

        try:
            provider = cls(self.modules_config)
        except:
            return self._internal_server_error()

        if provider.must_authenticate and user is None:
            self.code = 400
            self.message = 'Resource only available with HTTPS.'
            return

        if provider.write_enabled:
            self.dynamo_server.manager.master.lock()

            try:
                if self.dynamo_server.manager.master.inhibit_write():
                    # We need to give up here instead of waiting, because the web server processes will be flushed out as soon as
                    # inventory is updated after the current writing process is done
                    self.code = 503
                    self.message = 'Server cannot execute %s/%s at the moment because the inventory is being updated.' % (
                        module, command)
                    return
                else:
                    self.dynamo_server.manager.master.start_write_web(
                        socket.gethostname(), os.getpid())
                    # stop is called from the DynamoServer upon successful inventory update

            except:
                self.dynamo_server.manager.master.stop_write_web()
                raise

            finally:
                self.dynamo_server.manager.master.unlock()

        if provider.require_authorizer:
            if authorizer is None:
                authorizer = self.dynamo_server.manager.master.create_authorizer(
                )

            provider.authorizer = authorizer

        if provider.require_appmanager:
            provider.appmanager = self.dynamo_server.manager.master.create_appmanager(
            )

        try:
            ## Step 4
            post_request = None

            if environ['REQUEST_METHOD'] == 'POST':
                try:
                    content_type = environ['CONTENT_TYPE']
                except KeyError:
                    content_type = 'application/x-www-form-urlencoded'

                # In principle we should grab CONTENT_LENGTH from environ and only read as many bytes as given, but wsgi.input seems to know where the EOF is
                try:
                    content_length = environ['CONTENT_LENGTH']
                except KeyError:
                    # length -1: rely on wsgi.input having an EOF at the end
                    content_length = -1

                post_data = environ['wsgi.input'].read(content_length)

                # Even though our default content type is URL form, we check if this is a JSON
                try:
                    json_data = json.loads(post_data)
                except:
                    if content_type == 'application/json':
                        self.code = 400
                        self.message = 'Could not parse input.'
                        return
                else:
                    content_type = 'application/json'
                    provider.input_data = json_data
                    unicode2str(provider.input_data)

                if content_type == 'application/x-www-form-urlencoded':
                    try:
                        post_request = parse_qs(post_data)
                    except:
                        self.code = 400
                        self.message = 'Could not parse input.'
                elif content_type != 'application/json':
                    self.code = 400
                    self.message = 'Unknown Content-Type %s.' % content_type

            get_request = parse_qs(environ['QUERY_STRING'])

            if post_request is not None:
                for key, value in post_request.iteritems():
                    if key in get_request:
                        # return dict of parse_qs is {key: list}
                        get_request[key].extend(post_request[key])
                    else:
                        get_request[key] = post_request[key]

            unicode2str(get_request)

            request = {}
            for key, value in get_request.iteritems():
                if key.endswith('[]'):
                    key = key[:-2]
                    request[key] = map(escape, value)
                else:
                    if len(value) == 1:
                        request[key] = escape(value[0])
                    else:
                        request[key] = map(escape, value)

            ## Step 5
            caller = WebServer.User(user, dn, user_id, authlist)

            if self.dynamo_server.inventory.loaded:
                inventory = self.dynamo_server.inventory.create_proxy()
                if provider.write_enabled:
                    inventory._update_commands = []
            else:
                inventory = DummyInventory()

            content = provider.run(caller, request, inventory)

            if provider.write_enabled:
                self.dynamo_server._send_updates(inventory)

        except (exceptions.AuthorizationError, exceptions.ResponseDenied,
                exceptions.MissingParameter, exceptions.ExtraParameter,
                exceptions.IllFormedRequest, exceptions.InvalidRequest) as ex:
            self.code = 400
            self.message = str(ex)
            return
        except exceptions.TryAgain as ex:
            self.code = 503
            self.message = str(ex)
            return
        except:
            return self._internal_server_error()

        ## Step 6
        self.message = provider.message
        self.content_type = provider.content_type
        self.headers = provider.additional_headers
        if 'callback' in request:
            self.callback = request['callback']

        return content
예제 #7
0
    def _main(self, environ):
        """
        Body of the WSGI callable. Steps:
        1. Determine protocol. If HTTPS, identify the user.
        2. If js or css is requested, respond.
        3. Find the module class and instantiate it.
        4. Parse the query string into a dictionary.
        5. Call the run() function of the module class.
        6. Respond.
        """

        authorizer = None

        ## Step 1
        if environ['REQUEST_SCHEME'] == 'http':
            # No auth
            user, dn, user_id = None, None, 0
            authlist = []

        elif environ['REQUEST_SCHEME'] == 'https':
            authorizer = self.dynamo_server.manager.master.create_authorizer()

            # Client DN must match a known user
            try:
                dn = WebServer.format_dn(environ['SSL_CLIENT_S_DN'])
                userinfo = authorizer.identify_user(dn = dn, check_trunc = True)
                if userinfo is None:
                    raise exceptions.AuthorizationError()

                user, user_id, dn = userinfo

            except exceptions.AuthorizationError:
                self.code = 403
                self.message = 'Unknown user. Client name: %s' % environ['SSL_CLIENT_S_DN']
                return 
            except:
                return self._internal_server_error()

            authlist = authorizer.list_user_auth(user)

        else:
            self.code = 400
            self.message = 'Only HTTP or HTTPS requests are allowed.'
            return

        ## Step 2
        mode = environ['SCRIPT_NAME'].strip('/')

        if mode == 'js' or mode == 'css':
            try:
                source = open(HTMLMixin.contents_path + '/' + mode + environ['PATH_INFO'])
            except IOError:
                self.code = 404
                self.content_type = 'text/plain'
                return 'Invalid request %s%s.\n' % (mode, environ['PATH_INFO'])
            else:
                if mode == 'js':
                    self.content_type = 'text/javascript'
                else:
                    self.content_type = 'text/css'

                content = source.read() + '\n'
                source.close()

                return content

        ## Step 3
        if mode != 'data' and mode != 'web' and mode != 'registry' and mode != 'phedexdata': # registry and phedexdata for backward compatibility
            self.code = 404
            self.message = 'Invalid request %s.' % mode
            return

        if mode == 'phedexdata':
            mode = 'data'
            self.phedex_request = environ['PATH_INFO'][1:]

        module, _, command = environ['PATH_INFO'][1:].partition('/')

        try:
            cls = modules[mode][module][command]
        except KeyError:
            # Was a new module added perhaps?
            load_modules()
            try: # again
                cls = modules[mode][module][command]
            except KeyError:
                self.code = 404
                self.message = 'Invalid request %s/%s.' % (module, command)
                return

        try:
            provider = cls(self.modules_config)
        except:
            return self._internal_server_error()

        if provider.must_authenticate and user is None:
            self.code = 400
            self.message = 'Resource only available with HTTPS.'
            return

        if provider.write_enabled:
            self.dynamo_server.manager.master.lock()

            try:
                if self.dynamo_server.manager.master.inhibit_write():
                    # We need to give up here instead of waiting, because the web server processes will be flushed out as soon as
                    # inventory is updated after the current writing process is done
                    self.code = 503
                    self.message = 'Server cannot execute %s/%s at the moment because the inventory is being updated.' % (module, command)
                    return
                else:
                    self.dynamo_server.manager.master.start_write_web(socket.gethostname(), os.getpid())
                    # stop is called from the DynamoServer upon successful inventory update

            except:
                self.dynamo_server.manager.master.stop_write_web()
                raise

            finally:
                self.dynamo_server.manager.master.unlock()

        if provider.require_authorizer:
            if authorizer is None:
                authorizer = self.dynamo_server.manager.master.create_authorizer()

            provider.authorizer = authorizer

        if provider.require_appmanager:
            provider.appmanager = self.dynamo_server.manager.master.create_appmanager()

        try:
            ## Step 4
            post_request = None

            if environ['REQUEST_METHOD'] == 'POST':
                try:
                    content_type = environ['CONTENT_TYPE']
                except KeyError:
                    content_type = 'application/x-www-form-urlencoded'

                # In principle we should grab CONTENT_LENGTH from environ and only read as many bytes as given, but wsgi.input seems to know where the EOF is
                try:
                    content_length = environ['CONTENT_LENGTH']
                except KeyError:
                    # length -1: rely on wsgi.input having an EOF at the end
                    content_length = -1

                post_data = environ['wsgi.input'].read(content_length)

                # Even though our default content type is URL form, we check if this is a JSON
                try:
                    json_data = json.loads(post_data)
                except:
                    if content_type == 'application/json':
                        self.code = 400
                        self.message = 'Could not parse input.'
                        return
                else:
                    content_type = 'application/json'
                    provider.input_data = json_data
                    unicode2str(provider.input_data)

                if content_type == 'application/x-www-form-urlencoded':
                    try:
                        post_request = parse_qs(post_data)
                    except:
                        self.code = 400
                        self.message = 'Could not parse input.'
                elif content_type != 'application/json':
                    self.code = 400
                    self.message = 'Unknown Content-Type %s.' % content_type

            get_request = parse_qs(environ['QUERY_STRING'])

            if post_request is not None:
                for key, value in post_request.iteritems():
                    if key in get_request:
                        # return dict of parse_qs is {key: list}
                        get_request[key].extend(post_request[key])
                    else:
                        get_request[key] = post_request[key]

            unicode2str(get_request)

            request = {}
            for key, value in get_request.iteritems():
                if key.endswith('[]'):
                    key = key[:-2]
                    request[key] = map(escape, value)
                else:
                    if len(value) == 1:
                        request[key] = escape(value[0])
                    else:
                        request[key] = map(escape, value)

            ## Step 5
            caller = WebServer.User(user, dn, user_id, authlist)

            if self.dynamo_server.inventory.loaded:
                inventory = self.dynamo_server.inventory.create_proxy()
                if provider.write_enabled:
                    inventory._update_commands = []
            else:
                inventory = DummyInventory()

            content = provider.run(caller, request, inventory)

            if provider.write_enabled:
                self.dynamo_server._send_updates(inventory)
            
        except (exceptions.AuthorizationError, exceptions.ResponseDenied, exceptions.MissingParameter,
                exceptions.ExtraParameter, exceptions.IllFormedRequest, exceptions.InvalidRequest) as ex:
            self.code = 400
            self.message = str(ex)
            return
        except exceptions.TryAgain as ex:
            self.code = 503
            self.message = str(ex)
            return
        except:
            return self._internal_server_error()

        ## Step 6
        self.message = provider.message
        self.content_type = provider.content_type
        self.headers = provider.additional_headers
        if 'callback' in request:
            self.callback = request['callback']

        return content