Exemplo n.º 1
0
 def __init__(self, syncer=None, minimal=True):
     self.syncer = syncer
     self.minimal = minimal
     self.event_handler = MyFileSystemEventHandler(syncer=self.syncer)
     self.observer = Observer(timeout=20)
     self.paths = []
     if minimal:
         self.paths_minimal()
Exemplo n.º 2
0
    def __init__(self, ssl_private_key):

        self._ssl_private_key = ssl_private_key
        self._userdict = None
        self.reload_userdict()
        self._observer = Observer()
        self._observer.schedule(
            FileReloader("web-users.json", self.reload_userdict), get_home())
        self._observer.start()
Exemplo n.º 3
0
    def __init__(self, rmq_mgmt, ssl_public_key):

        self._rmq_mgmt = rmq_mgmt
        self._ssl_public_key = ssl_public_key
        self._userdict = None
        self.reload_userdict()
        self._observer = Observer()
        self._observer.schedule(
            FileReloader("web-users.json", self.reload_userdict), get_home())
        self._observer.start()
        self._certs = Certs()
Exemplo n.º 4
0
    def __init__(self, tls_private_key=None, web_secret_key=None):

        self._tls_private_key = tls_private_key
        self._web_secret_key = web_secret_key
        if self._tls_private_key is None and self._web_secret_key is None:
            raise ValueError("Must have either ssl_private_key or web_secret_key specified!")
        if self._tls_private_key is not None and self._web_secret_key is not None:
            raise ValueError("Must use either ssl_private_key or web_secret_key not both!")
        self._userdict = None
        self.reload_userdict()
        self._observer = Observer()
        self._observer.schedule(
            VolttronHomeFileReloader("web-users.json", self.reload_userdict),
            get_home()
        )
        self._observer.start()
Exemplo n.º 5
0
class FileSystemMonitor:
    def __init__(self, syncer=None, minimal=True):
        self.syncer = syncer
        self.minimal = minimal
        self.event_handler = MyFileSystemEventHandler(syncer=self.syncer)
        self.observer = Observer(timeout=20)
        self.paths = []
        if minimal:
            self.paths_minimal()

    def _log_info(self, msg):
        print(" - %s" % msg)

    def paths_minimal(self):
        self.paths = []
        for item in [
                "jumpscaleX_core/JumpscaleCore",
                "jumpscaleX_core/cmds",
                "jumpscaleX_core/install",
                # "jumpscaleX_libs",
                # "jumpscaleX_threebot",
                # "jumpscaleX_builders",
                # "jumpscaleX_libs_extra",
                # "jumpscaleX_weblibs",
        ]:
            self.paths.append(
                "{DIR_CODE}/github/threefoldtech/%s:/sandbox/code/github/threefoldtech/%s"
                % (item, item))

    def _get_paths(self):
        if self.paths != []:
            return self.syncer._get_paths(paths=self.paths)
        else:
            return self.syncer._get_paths()

    def start(self):

        for item in self._get_paths():
            source, dest = item
            self._log_info("monitor:%s" % source)
            self.observer.schedule(self.event_handler, source, recursive=True)

        self.observer.start()

        self._log_info("WE ARE MONITORING ")

        try:
            while True:
                gevent.time.sleep(1)
                # print(1)
        except KeyboardInterrupt:
            self.observer.stop()
        self.observer.join()

    def __str__(self):
        return "FileSystemMonitor"
Exemplo n.º 6
0
    def __init__(self,
                 rmq_mgmt=None,
                 ssl_public_key: bytes = None,
                 rpc_caller=None):

        self._rpc_caller = rpc_caller
        self._rmq_mgmt = rmq_mgmt
        self._certs = None

        if rmq_mgmt is not None:
            self._certs = Certs()

        self._pending_auths = None
        self._denied_auths = None
        self._approved_auths = None

        if ssl_public_key is None:
            self._insecure_mode = True
        else:
            self._insecure_mode = False

        # must have a none value for when we don't have an ssl context available.
        if ssl_public_key is not None:
            if isinstance(ssl_public_key, bytes):
                self._ssl_public_key = ssl_public_key.decode('utf-8')
            elif isinstance(ssl_public_key, str):
                self._ssl_public_key = ssl_public_key

            else:
                raise ValueError("Invalid type for ssl_public_key")
        else:
            self._ssl_public_key = None

        self._userdict = None
        self.reload_userdict()

        self._observer = Observer()
        self._observer.schedule(
            VolttronHomeFileReloader("web-users.json", self.reload_userdict),
            get_home())
        self._observer.start()
        if ssl_public_key is not None:
            self._certs = Certs()
Exemplo n.º 7
0
def test_can_watch_for_changes_with_gevent():
    # Given a gevent-based thread that counts stuff and sleeps every second
    count = 0

    def counter():
        nonlocal count
        while True:
            count += 1
            time.sleep(1)

    counter_thread = Thread(target=counter, daemon=True)
    counter_thread.start()

    # And an event handler that gets notified when this file changes
    events = []

    class Handler(FileSystemEventHandler):
        def on_any_event(self, event):
            events.append(event)

    # And an observer that dispatches to that handler
    try:
        observer = Observer()
        observer.schedule(Handler(), rel(".."), recursive=True)
        observer.start()

        # When I touch this file
        subprocess.run(["touch", __file__])

        # And wait a second
        time.sleep(1)

        # Then the counter should have incremented
        assert count >= 2

        # And the event should have been observed
        assert events == [FileModifiedEvent(__file__)]
    finally:
        observer.stop()
        observer.join()
Exemplo n.º 8
0
    def __init__(self,
                 tls_private_key=None,
                 tls_public_key=None,
                 web_secret_key=None):

        self.refresh_token_timeout = 240  # minutes before token expires. TODO: Should this be a setting somewhere?
        self.access_token_timeout = 15  # minutes before token expires. TODO: Should this be a setting somewhere?
        self._tls_private_key = tls_private_key
        self._tls_public_key = tls_public_key
        self._web_secret_key = web_secret_key
        if self._tls_private_key is None and self._web_secret_key is None:
            raise ValueError(
                "Must have either ssl_private_key or web_secret_key specified!"
            )
        if self._tls_private_key is not None and self._web_secret_key is not None:
            raise ValueError(
                "Must use either ssl_private_key or web_secret_key not both!")
        self._userdict = None
        self.reload_userdict()
        self._observer = Observer()
        self._observer.schedule(
            VolttronHomeFileReloader("web-users.json", self.reload_userdict),
            get_home())
        self._observer.start()
Exemplo n.º 9
0
def watch_file_with_fullpath(fullpath, callback):
    """Run callback method whenever the file changes

        Not available on OS X/MacOS.
    """
    dirname, filename = os.path.split(fullpath)
    _log.info("Adding file watch for %s", fullpath)
    _observer = Observer()
    _observer.schedule(AbsolutePathFileReloader(fullpath, callback), dirname)
    _log.info("Added file watch for %s", fullpath)
    _observer.start()
Exemplo n.º 10
0
def watch_file(fullpath, callback):
    """Run callback method whenever the file changes

        Not available on OS X/MacOS.
    """

    dirname, filename = os.path.split(fullpath)
    _log.info("Adding file watch for %s dirname=%s, filename=%s", fullpath,
              get_home(), filename)
    observer = Observer()
    observer.schedule(VolttronHomeFileReloader(filename, callback),
                      path=get_home())
    observer.start()
    _log.info("Added file watch for %s", fullpath)
Exemplo n.º 11
0
class AuthenticateEndpoints(object):

    def __init__(self, ssl_private_key):

        self._ssl_private_key = ssl_private_key
        self._userdict = None
        self.reload_userdict()
        self._observer = Observer()
        self._observer.schedule(
            FileReloader("web-users.json", self.reload_userdict),
            get_home()
        )
        self._observer.start()

    def reload_userdict(self):
        webuserpath = os.path.join(get_home(), 'web-users.json')
        self._userdict = PersistentDict(webuserpath)

    def get_routes(self):
        """
        Returns a list of tuples with the routes for authentication.

        Tuple should have the following:

            - regular expression for calling the endpoint
            - 'callable' keyword specifying that a method is being specified
            - the method that should be used to call when the regular expression matches

        code:

            return [
                (re.compile('^/csr/request_new$'), 'callable', self._csr_request_new)
            ]

        :return:
        """
        return [
            (re.compile('^/authenticate'), 'callable', self.get_auth_token)
        ]

    def get_auth_token(self, env, data):
        """
        Creates an authentication token to be returned to the caller.  The
        response will be a text/plain encoded user

        :param env:
        :param data:
        :return:
        """
        if env.get('REQUEST_METHOD') != 'POST':
            _log.warning("Authentication must use POST request.")
            return Response('', status='401 Unauthorized')

        assert len(self._userdict) > 0, "No users in user dictionary, set the master password first!"

        if not isinstance(data, dict):
            _log.debug("data is not a dict, decoding")
            decoded = dict((k, v if len(v) > 1 else v[0])
                           for k, v in urlparse.parse_qs(data).iteritems())

            username = decoded.get('username')
            password = decoded.get('password')

        else:
            username = data.get('username')
            password = data.get('password')

        _log.debug("Username is: {}".format(username))

        error = ""
        if username is None:
            error += "Invalid username passed"
        if not password:
            error += "Invalid password passed"

        if error:
            _log.error("Invalid parameters passed: {}".format(error))
            return Response(error, status='401')

        user = self.__get_user(username, password)
        if user is None:
            _log.error("No matching user for passed username: {}".format(username))
            return Response('', status='401')

        encoded = jwt.encode(user, self._ssl_private_key, algorithm='RS256').encode('utf-8')

        return Response(encoded, '200 OK', content_type='text/plain')

    def __get_user(self, username, password):
        """
        Retrieve user from the user store based upon username/password

        The hashed_password will not be returned with the value in the user
        object.

        If there is not a username/password that match return None.

        :param username:
        :param password:
        :return:
        """
        user = self._userdict.get(username)
        if user is not None:
            hashed_pass = user.get('hashed_password')
            if hashed_pass and argon2.verify(password, hashed_pass):
                usr_cpy = user.copy()
                del usr_cpy['hashed_password']
                return usr_cpy
        return None
Exemplo n.º 12
0
class AdminEndpoints(object):
    def __init__(self, rmq_mgmt, ssl_public_key):

        self._rmq_mgmt = rmq_mgmt
        self._ssl_public_key = ssl_public_key
        self._userdict = None
        self.reload_userdict()
        self._observer = Observer()
        self._observer.schedule(
            FileReloader("web-users.json", self.reload_userdict), get_home())
        self._observer.start()
        self._certs = Certs()

    def reload_userdict(self):
        webuserpath = os.path.join(get_home(), 'web-users.json')
        self._userdict = PersistentDict(webuserpath)

    def get_routes(self):
        """
        Returns a list of tuples with the routes for the adminstration endpoints
        available in it.

        :return:
        """
        return [(re.compile('^/admin.*'), 'callable', self.admin)]

    def admin(self, env, data):
        if len(self._userdict) == 0:
            if env.get('REQUEST_METHOD') == 'POST':
                decoded = dict((k, v if len(v) > 1 else v[0])
                               for k, v in urlparse.parse_qs(data).iteritems())
                username = decoded.get('username')
                pass1 = decoded.get('password1')
                pass2 = decoded.get('password2')
                if pass1 == pass2 and pass1 is not None:
                    _log.debug("Setting master password")
                    self.add_user(username, pass1, groups=['admin'])
                    return Response('',
                                    status='302',
                                    headers={'Location': '/admin/login.html'})

            template = template_env(env).get_template('first.html')
            return Response(template.render())

        if 'login.html' in env.get('PATH_INFO') or '/admin/' == env.get(
                'PATH_INFO'):
            template = template_env(env).get_template('login.html')
            return Response(template.render())

        return self.verify_and_dispatch(env, data)

    def verify_and_dispatch(self, env, data):
        """ Verify that the user is an admin and dispatch

        :param env: web environment
        :param data: data associated with a web form or json/xml request data
        :return: Response object.
        """
        from volttron.platform.web import get_user_claims, NotAuthorized
        try:
            claims = get_user_claims(env)
        except NotAuthorized:
            _log.error("Unauthorized user attempted to connect to {}".format(
                env.get('PATH_INFO')))
            return Response('<h1>Unauthorized User</h1>',
                            status="401 Unauthorized")

        # Make sure we have only admins for viewing this.
        if 'admin' not in claims.get('groups'):
            return Response('<h1>Unauthorized User</h1>',
                            status="401 Unauthorized")

        # Make sure we have only admins for viewing this.
        if 'admin' not in claims.get('groups'):
            return Response('<h1>Unauthorized User</h1>',
                            status="401 Unauthorized")

        path_info = env.get('PATH_INFO')
        if path_info.startswith('/admin/api/'):
            return self.__api_endpoint(path_info[len('/admin/api/'):], data)

        if path_info.endswith('html'):
            page = path_info.split('/')[-1]
            try:
                template = template_env(env).get_template(page)
            except TemplateNotFound:
                return Response("<h1>404 Not Found</h1>",
                                status="404 Not Found")

            if page == 'list_certs.html':
                html = template.render(
                    certs=self._certs.get_all_cert_subjects())
            elif page == 'pending_csrs.html':
                html = template.render(
                    csrs=self._certs.get_pending_csr_requests())
            else:
                # A template with no params.
                html = template.render()

            return Response(html)

        template = template_env(env).get_template('index.html')
        resp = template.render()
        return Response(resp)

    def __api_endpoint(self, endpoint, data):
        _log.debug("Doing admin endpoint {}".format(endpoint))
        if endpoint == 'certs':
            response = self.__cert_list_api()
        elif endpoint == 'pending_csrs':
            response = self.__pending_csrs_api()
        elif endpoint.startswith('approve_csr/'):
            response = self.__approve_csr_api(endpoint.split('/')[1])
        elif endpoint.startswith('deny_csr/'):
            response = self.__deny_csr_api(endpoint.split('/')[1])
        elif endpoint.startswith('delete_csr/'):
            response = self.__delete_csr_api(endpoint.split('/')[1])
        else:
            response = Response(
                '{"status": "Unknown endpoint {}"}'.format(endpoint),
                content_type="application/json")
        return response

    def __approve_csr_api(self, common_name):
        try:
            _log.debug("Creating cert and permissions for user: {}".format(
                common_name))
            self._certs.approve_csr(common_name)
            permissions = self._rmq_mgmt.get_default_permissions(common_name)
            self._rmq_mgmt.create_user_with_permissions(
                common_name, permissions, True)
            data = dict(status=self._certs.get_csr_status(common_name),
                        cert=self._certs.get_cert_from_csr(common_name))
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(json.dumps(data), content_type="application/json")

    def __deny_csr_api(self, common_name):
        try:
            self._certs.deny_csr(common_name)
            data = dict(status="DENIED",
                        message="The administrator has denied the request")
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(json.dumps(data), content_type="application/json")

    def __delete_csr_api(self, common_name):
        try:
            self._certs.delete_csr(common_name)
            data = dict(status="DELETED",
                        message="The administrator has denied the request")
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(json.dumps(data), content_type="application/json")

    def __pending_csrs_api(self):
        csrs = [c for c in self._certs.get_pending_csr_requests()]
        return Response(json.dumps(csrs), content_type="application/json")

    def __cert_list_api(self):

        subjects = [
            dict(common_name=x.common_name)
            for x in self._certs.get_all_cert_subjects()
        ]
        return Response(json.dumps(subjects), content_type="application/json")

    def add_user(self, username, unencrypted_pw, groups=[], overwrite=False):
        if self._userdict.get(username):
            raise ValueError("Already exists!")
        if groups is None:
            groups = []
        hashed_pass = argon2.hash(unencrypted_pw)
        self._userdict[username] = dict(hashed_password=hashed_pass,
                                        groups=groups)
        self._userdict.async_sync()
Exemplo n.º 13
0
class AuthenticateEndpoints(object):
    def __init__(self,
                 tls_private_key=None,
                 tls_public_key=None,
                 web_secret_key=None):

        self.refresh_token_timeout = 240  # minutes before token expires. TODO: Should this be a setting somewhere?
        self.access_token_timeout = 15  # minutes before token expires. TODO: Should this be a setting somewhere?
        self._tls_private_key = tls_private_key
        self._tls_public_key = tls_public_key
        self._web_secret_key = web_secret_key
        if self._tls_private_key is None and self._web_secret_key is None:
            raise ValueError(
                "Must have either ssl_private_key or web_secret_key specified!"
            )
        if self._tls_private_key is not None and self._web_secret_key is not None:
            raise ValueError(
                "Must use either ssl_private_key or web_secret_key not both!")
        self._userdict = None
        self.reload_userdict()
        self._observer = Observer()
        self._observer.schedule(
            VolttronHomeFileReloader("web-users.json", self.reload_userdict),
            get_home())
        self._observer.start()

    def reload_userdict(self):
        webuserpath = os.path.join(get_home(), 'web-users.json')
        self._userdict = PersistentDict(webuserpath)

    def get_routes(self):
        """
        Returns a list of tuples with the routes for authentication.

        Tuple should have the following:

            - regular expression for calling the endpoint
            - 'callable' keyword specifying that a method is being specified
            - the method that should be used to call when the regular expression matches

        code:

            return [
                (re.compile('^/csr/request_new$'), 'callable', self._csr_request_new)
            ]

        :return:
        """
        return [(re.compile('^/authenticate'), 'callable',
                 self.handle_authenticate)]

    def handle_authenticate(self, env, data):
        """
        Callback for /authenticate endpoint.

        Routes request based on HTTP method and returns a text/plain encoded token or error.

        :param env:
        :param data:
        :return: Response
        """
        method = env.get('REQUEST_METHOD')
        if method == 'POST':
            response = self.get_auth_tokens(env, data)
        elif method == 'PUT':
            response = self.renew_auth_token(env, data)
        elif method == 'DELETE':
            response = self.revoke_auth_token(env, data)
        else:
            error = f"/authenticate endpoint accepts only POST, PUT, or DELETE methods. Received: {method}"
            _log.warning(error)
            return Response(error,
                            status='405 Method Not Allowed',
                            content_type='text/plain')
        return response

    def get_auth_tokens(self, env, data):
        """
        Creates an authentication refresh and acccss tokens to be returned to the caller.  The
        response will be a text/plain encoded user.  Data should contain:
        {
            "username": "******",
            "password": "******"
        }
        :param env:
        :param data:
        :return:
        """

        assert len(
            self._userdict
        ) > 0, "No users in user dictionary, set the administrator password first!"

        if not isinstance(data, dict):
            _log.debug("data is not a dict, decoding")
            decoded = dict((k, v if len(v) > 1 else v[0])
                           for k, v in parse_qs(data).items())

            username = decoded.get('username')
            password = decoded.get('password')

        else:
            username = data.get('username')
            password = data.get('password')

        _log.debug("Username is: {}".format(username))

        error = ""
        if username is None:
            error += "Invalid username passed"
        if not password:
            error += "Invalid password passed"

        if error:
            _log.error("Invalid parameters passed: {}".format(error))
            return Response(error, status='401')

        user = self.__get_user(username, password)
        if user is None:
            _log.error(
                "No matching user for passed username: {}".format(username))
            return Response('', status='401')
        access_token, refresh_token = self._get_tokens(user)
        response = Response(json.dumps({
            "refresh_token": refresh_token,
            "access_token": access_token
        }),
                            content_type="application/json")
        return response

    def _get_tokens(self, claims):
        now = datetime.utcnow()
        claims['iat'] = now
        claims['nbf'] = now
        claims['exp'] = now + timedelta(minutes=self.access_token_timeout)
        claims['grant_type'] = 'access_token'
        algorithm = 'RS256' if self._tls_private_key is not None else 'HS256'
        encode_key = self._tls_private_key if algorithm == 'RS256' else self._web_secret_key
        access_token = jwt.encode(claims, encode_key, algorithm=algorithm)
        claims['exp'] = now + timedelta(minutes=self.refresh_token_timeout)
        claims['grant_type'] = 'refresh_token'
        refresh_token = jwt.encode(claims, encode_key, algorithm=algorithm)
        return access_token.decode('utf-8'), refresh_token.decode('utf8')

    def renew_auth_token(self, env, data):
        """
        Creates a new authentication access token to be returned to the caller.  The
        response will be a text/plain encoded user.  Request should contain:
            • Content Type: application/json
            • Authorization: BEARER <jwt_refresh_token>
            • Body (optional):
                {
                "current_access_token": "<jwt_access_token>"
                }

        :param env:
        :param data:
        :return:
        """
        current_access_token = data.get('current_access_token')
        from volttron.platform.web import get_bearer, get_user_claim_from_bearer, NotAuthorized
        try:
            current_refresh_token = get_bearer(env)
            claims = get_user_claim_from_bearer(
                current_refresh_token,
                web_secret_key=self._web_secret_key,
                tls_public_key=self._tls_public_key)
        except NotAuthorized:
            _log.error("Unauthorized user attempted to connect to {}".format(
                env.get('PATH_INFO')))
            return Response('Unauthorized User', status="401 Unauthorized")

        except jwt.ExpiredSignatureError:
            _log.error(
                "User attempted to connect to {} with an expired signature".
                format(env.get('PATH_INFO')))
            return Response('Unauthorized User', status="401 Unauthorized")

        if claims.get('grant_type') != 'refresh_token' or not claims.get(
                'groups'):
            return Response('Invalid refresh token.',
                            status="401 Unauthorized")
        else:
            # TODO: Consider blacklisting and reissuing refresh tokens also when used.
            new_access_token, _ = self._get_tokens(claims)
            if current_access_token:
                pass  # TODO: keep current subscriptions? blacklist old token?
            return Response(json.dumps({"access_token": new_access_token}),
                            content_type="application/json")

    def revoke_auth_token(self, env, data):
        # TODO: Blacklist old token? Immediately close websockets?
        return Response('DELETE /authenticate is not yet implemented',
                        status='501 Not Implemented',
                        content_type='text/plain')

    def __get_user(self, username, password):
        """
        Retrieve user from the user store based upon username/password

        The hashed_password will not be returned with the value in the user
        object.

        If there is not a username/password that match return None.

        :param username:
        :param password:
        :return:
        """
        user = self._userdict.get(username)
        if user is not None:
            hashed_pass = user.get('hashed_password')
            if hashed_pass and argon2.verify(password, hashed_pass):
                usr_cpy = user.copy()
                del usr_cpy['hashed_password']
                return usr_cpy
        return None
Exemplo n.º 14
0
class AdminEndpoints(object):
    def __init__(self,
                 rmq_mgmt=None,
                 ssl_public_key: bytes = None,
                 rpc_caller=None):

        self._rpc_caller = rpc_caller
        self._rmq_mgmt = rmq_mgmt

        self._pending_auths = None
        self._denied_auths = None
        self._approved_auths = None

        if ssl_public_key is None:
            self._insecure_mode = True
        else:
            self._insecure_mode = False

        # must have a none value for when we don't have an ssl context available.
        if ssl_public_key is not None:
            if isinstance(ssl_public_key, bytes):
                self._ssl_public_key = ssl_public_key.decode('utf-8')
            elif isinstance(ssl_public_key, str):
                self._ssl_public_key = ssl_public_key

            else:
                raise ValueError("Invalid type for ssl_public_key")
        else:
            self._ssl_public_key = None

        self._userdict = None
        self.reload_userdict()

        self._observer = Observer()
        self._observer.schedule(
            VolttronHomeFileReloader("web-users.json", self.reload_userdict),
            get_home())
        self._observer.start()

    def reload_userdict(self):
        webuserpath = os.path.join(get_home(), 'web-users.json')
        self._userdict = PersistentDict(webuserpath, format="json")

    def get_routes(self):
        """
        Returns a list of tuples with the routes for the administration endpoints
        available in it.

        :return:
        """
        return [(re.compile('^/admin.*'), 'callable', self.admin)]

    def admin(self, env, data):
        if len(self._userdict) == 0:
            if env.get('REQUEST_METHOD') == 'POST':
                decoded = dict((k, v if len(v) > 1 else v[0])
                               for k, v in parse_qs(data).items())
                username = decoded.get('username')
                pass1 = decoded.get('password1')
                pass2 = decoded.get('password2')

                if pass1 == pass2 and pass1 is not None:
                    _log.debug("Setting administrator password")
                    self.add_user(username, pass1, groups=['admin'])
                    return Response('',
                                    status='302',
                                    headers={'Location': '/admin/login.html'})

            template = template_env(env).get_template('first.html')
            return Response(template.render(), content_type="text/html")

        if 'login.html' in env.get('PATH_INFO') or '/admin/' == env.get(
                'PATH_INFO'):
            template = template_env(env).get_template('login.html')
            _log.debug("Login.html: {}".format(env.get('PATH_INFO')))
            return Response(template.render(), content_type='text/html')

        return self.verify_and_dispatch(env, data)

    def verify_and_dispatch(self, env, data):
        """ Verify that the user is an admin and dispatch

        :param env: web environment
        :param data: data associated with a web form or json/xml request data
        :return: Response object.
        """
        from volttron.platform.web import get_bearer, NotAuthorized
        try:
            claims = self._rpc_caller(PLATFORM_WEB, 'get_user_claims',
                                      get_bearer(env)).get()
        except NotAuthorized:
            _log.error("Unauthorized user attempted to connect to {}".format(
                env.get('PATH_INFO')))
            return Response('<h1>Unauthorized User</h1>',
                            status="401 Unauthorized")
        except RemoteError as e:
            if "ExpiredSignatureError" in e.exc_info["exc_type"]:
                _log.warning(
                    "Access token has expired! Please re-login to renew.")
                template = template_env(env).get_template('login.html')
                _log.debug("Login.html: {}".format(env.get('PATH_INFO')))
                return Response(template.render(), content_type='text/html')
            else:
                _log.error(e)

        # Make sure we have only admins for viewing this.
        if 'admin' not in claims.get('groups'):
            return Response('<h1>Unauthorized User</h1>',
                            status="401 Unauthorized")

        path_info = env.get('PATH_INFO')
        if path_info.startswith('/admin/api/'):
            return self.__api_endpoint(path_info[len('/admin/api/'):], data)

        if path_info.endswith('html'):
            page = path_info.split('/')[-1]
            try:
                template = template_env(env).get_template(page)
            except TemplateNotFound:
                return Response("<h1>404 Not Found</h1>",
                                status="404 Not Found")

            if page == 'pending_auth_reqs.html':
                try:
                    self._pending_auths = self._rpc_caller.call(
                        AUTH, 'get_authorization_pending').get(timeout=2)
                    self._denied_auths = self._rpc_caller.call(
                        AUTH, 'get_authorization_denied').get(timeout=2)
                    self._approved_auths = self._rpc_caller.call(
                        AUTH, 'get_authorization_approved').get(timeout=2)
                except TimeoutError:
                    self._pending_auths = []
                    self._denied_auths = []
                    self._approved_auths = []
                # When messagebus is rmq, include pending csrs in the output pending_auth_reqs.html page
                if self._rmq_mgmt is not None:
                    html = template.render(csrs=self._rpc_caller.call(
                        AUTH, 'get_pending_csrs').get(timeout=4),
                                           auths=self._pending_auths,
                                           denied_auths=self._denied_auths,
                                           approved_auths=self._approved_auths)
                else:
                    html = template.render(auths=self._pending_auths,
                                           denied_auths=self._denied_auths,
                                           approved_auths=self._approved_auths)
            else:
                # A template with no params.
                html = template.render()

            return Response(html)

        template = template_env(env).get_template('index.html')
        resp = template.render()
        return Response(resp)

    def __api_endpoint(self, endpoint, data):
        _log.debug("Doing admin endpoint {}".format(endpoint))
        if endpoint == 'certs':
            response = self.__cert_list_api()
        elif endpoint == 'pending_csrs':
            response = self.__pending_csrs_api()
        elif endpoint.startswith('approve_csr/'):
            response = self.__approve_csr_api(endpoint.split('/')[1])
        elif endpoint.startswith('deny_csr/'):
            response = self.__deny_csr_api(endpoint.split('/')[1])
        elif endpoint.startswith('delete_csr/'):
            response = self.__delete_csr_api(endpoint.split('/')[1])
        elif endpoint.startswith('approve_credential/'):
            response = self.__approve_credential_api(endpoint.split('/')[1])
        elif endpoint.startswith('deny_credential/'):
            response = self.__deny_credential_api(endpoint.split('/')[1])
        elif endpoint.startswith('delete_credential/'):
            response = self.__delete_credential_api(endpoint.split('/')[1])
        else:
            response = Response(
                '{"status": "Unknown endpoint {}"}'.format(endpoint),
                content_type="application/json")
        return response

    def __approve_csr_api(self, common_name):
        try:
            _log.debug("Creating cert and permissions for user: {}".format(
                common_name))
            self._rpc_caller.call(AUTH, 'approve_authorization_failure',
                                  common_name).wait(timeout=4)
            data = dict(
                status=self._rpc_caller.call(AUTH, "get_pending_csr_status",
                                             common_name).get(timeout=2),
                cert=self._rpc_caller.call(AUTH, "get_pending_csr_cert",
                                           common_name).get(timeout=2))
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        except TimeoutError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(jsonapi.dumps(data), content_type="application/json")

    def __deny_csr_api(self, common_name):
        try:
            self._rpc_caller.call(AUTH, 'deny_authorization_failure',
                                  common_name).wait(timeout=2)
            data = dict(status="DENIED",
                        message="The administrator has denied the request")
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        except TimeoutError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(jsonapi.dumps(data), content_type="application/json")

    def __delete_csr_api(self, common_name):
        try:
            self._rpc_caller.call(AUTH, 'delete_authorization_failure',
                                  common_name).wait(timeout=2)
            data = dict(status="DELETED",
                        message="The administrator has denied the request")
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        except TimeoutError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(jsonapi.dumps(data), content_type="application/json")

    def __pending_csrs_api(self):
        try:
            data = self._rpc_caller.call(AUTH,
                                         'get_pending_csrs').get(timeout=4)

        except TimeoutError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(jsonapi.dumps(data), content_type="application/json")

    def __cert_list_api(self):

        try:
            data = [
                dict(common_name=x.common_name) for x in self._rpc_caller.call(
                    AUTH, "get_all_pending_csr_subjects").get(timeout=2)
            ]

        except TimeoutError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(jsonapi.dumps(data), content_type="application/json")

    def __approve_credential_api(self, user_id):
        try:
            _log.debug(
                "Creating credential and permissions for user: {}".format(
                    user_id))
            self._rpc_caller.call(AUTH, 'approve_authorization_failure',
                                  user_id).wait(timeout=4)
            data = dict(status='APPROVED',
                        message="The administrator has approved the request")
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        except TimeoutError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(jsonapi.dumps(data), content_type="application/json")

    def __deny_credential_api(self, user_id):
        try:
            self._rpc_caller.call(AUTH, 'deny_authorization_failure',
                                  user_id).wait(timeout=2)
            data = dict(status="DENIED",
                        message="The administrator has denied the request")
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        except TimeoutError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(jsonapi.dumps(data), content_type="application/json")

    def __delete_credential_api(self, user_id):
        try:
            self._rpc_caller.call(AUTH, 'delete_authorization_failure',
                                  user_id).wait(timeout=2)
            data = dict(status="DELETED",
                        message="The administrator has denied the request")
        except ValueError as e:
            data = dict(status="ERROR", message=e.message)

        except TimeoutError as e:
            data = dict(status="ERROR", message=e.message)

        return Response(jsonapi.dumps(data), content_type="application/json")

    def add_user(self, username, unencrypted_pw, groups=None, overwrite=False):
        if self._userdict.get(username) and not overwrite:
            raise ValueError(
                f"The user {username} is already present and overwrite not set to True"
            )
        if groups is None:
            groups = []
        hashed_pass = argon2.hash(unencrypted_pw)
        self._userdict[username] = dict(hashed_password=hashed_pass,
                                        groups=groups)

        self._userdict.sync()
Exemplo n.º 15
0
from threading import Thread

logging.basicConfig(level=logging.DEBUG)

running = True


def printer():
    global running
    logger = logging.getLogger("printer")
    while running:
        logger.info("Ping!")
        time.sleep(1)


try:
    pinger = Thread(target=printer)
    pinger.start()

    observer = Observer()
    observer.schedule(LoggingEventHandler(), ".", recursive=True)
    observer.start()

    while True:
        time.sleep(1)
except KeyboardInterrupt:
    running = False
    observer.stop()

observer.join()
Exemplo n.º 16
0
def startFileSystemObservation():
    observer = Observer()
    observer.schedule(CsvProcessingHandler(),
                      environ.get("CRIMES_DATA_DIR", DEFAULT_DATA_DIR),
                      recursive=False)
    observer.start()