Beispiel #1
0
def example_policies(cls):
    """
    This function gets registered under 'example' in the
    :attr:`gateone.ApplicationWebSocket.security` dict and is called by the
    :func:`auth.require` decorator by way of the :class:`auth.policies`
    sub-function. It returns ``True`` or ``False`` depending on what is defined
    in the settings dir and what function is being called.
    """
    instance = cls.instance  # Your Application instance
    function = cls.function  # Wrapped function
    f_args = cls.f_args  # Wrapped function's arguments
    f_kwargs = cls.f_kwargs  # Wrapped function's keyword arguments
    # This is a convenient way to map function/method names to specific policy
    # functions:
    policy_functions = {
        'test_example': policy_test_example,
    }
    user = instance.current_user
    # The applicable_policies() function takes an application 'scope', a user
    # dict (must have a 'upn' key), and a dict that contains all of Gate One's
    # settings (always available via ApplicationWebSocket.prefs) and returns
    # a single dict containing the merged settings (aka policies) for that
    # scope.
    # In other words, if you have this inside a file in gateone/settings/:
    #    {
    #        "*": {
    #            "example": {
    #                "foo": "bar"
    #            }
    #        },
    #        "[email protected]": {
    #            "example": {
    #                "foo": "joe!"
    #            }
    #        }
    #    }
    #
    # applicable_policies() would return:
    #
    #    {"foo": "bar"}
    #
    # for regular users but [email protected] would get:
    #
    #    {"foo": "joe!"}
    policy = applicable_policies('example', user, instance.ws.prefs)
    if not policy:  # No policies found for the given scope
        return True  # A world without limits!
    # Check the basics first...  Is {"allow": true}?
    if 'allow' in policy:  # Only check this if there's an "allow" somewhere
        if not policy['allow']:  # User is DENIED!
            example_log.error(
                _("%s denied access to the Example application by policy." %
                  user['upn']))
            return False
    # Here we run through our policy_functions dict and call the appropriate
    # policy-checking function that matches the decorated method's name:
    if function.__name__ in policy_functions:
        return policy_functions[function.__name__](cls, policy)
    return True  # Default to permissive if we made it this far
Beispiel #2
0
def example_policies(cls):
    """
    This function gets registered under 'example' in the
    :attr:`gateone.ApplicationWebSocket.security` dict and is called by the
    :func:`auth.require` decorator by way of the :class:`auth.policies`
    sub-function. It returns ``True`` or ``False`` depending on what is defined
    in the settings dir and what function is being called.
    """
    instance = cls.instance # Your Application instance
    function = cls.function # Wrapped function
    f_args = cls.f_args     # Wrapped function's arguments
    f_kwargs = cls.f_kwargs # Wrapped function's keyword arguments
    # This is a convenient way to map function/method names to specific policy
    # functions:
    policy_functions = {
        'test_example': policy_test_example,
    }
    user = instance.current_user
    # The applicable_policies() function takes an application 'scope', a user
    # dict (must have a 'upn' key), and a dict that contains all of Gate One's
    # settings (always available via ApplicationWebSocket.prefs) and returns
    # a single dict containing the merged settings (aka policies) for that
    # scope.
    # In other words, if you have this inside a file in gateone/settings/:
    #    {
    #        "*": {
    #            "example": {
    #                "foo": "bar"
    #            }
    #        },
    #        "[email protected]": {
    #            "example": {
    #                "foo": "joe!"
    #            }
    #        }
    #    }
    #
    # applicable_policies() would return:
    #
    #    {"foo": "bar"}
    #
    # for regular users but [email protected] would get:
    #
    #    {"foo": "joe!"}
    policy = applicable_policies('example', user, instance.ws.prefs)
    if not policy: # No policies found for the given scope
        return True # A world without limits!
    # Check the basics first...  Is {"allow": true}?
    if 'allow' in policy: # Only check this if there's an "allow" somewhere
        if not policy['allow']: # User is DENIED!
            example_log.error(_(
                "%s denied access to the Example application by policy."
                % user['upn']))
            return False
    # Here we run through our policy_functions dict and call the appropriate
    # policy-checking function that matches the decorated method's name:
    if function.__name__ in policy_functions:
        return policy_functions[function.__name__](cls, policy)
    return True # Default to permissive if we made it this far
Beispiel #3
0
def terminal_policies(cls):
    """
    This function gets registered under 'terminal' in the
    :attr:`ApplicationWebSocket.security` dict and is called by the
    :func:`require` decorator by way of the :class:`policies` sub-function. It
    returns True or False depending on what is defined in the settings dir and
    what function is being called.

    This function will keep track of and place limmits on the following:

        * The number of open terminals.
        * How big each terminal may be.
        * Who may view or write to a shared terminal.

    If no 'terminal' policies are defined this function will always return True.
    """
    instance = cls.instance  # TerminalApplication instance
    function = cls.function  # Wrapped function
    #f_args = cls.f_args     # Wrapped function's arguments
    #f_kwargs = cls.f_kwargs # Wrapped function's keyword arguments
    policy_functions = {
        'new_terminal': policy_new_terminal,
        'resize': policy_write_check_dict,
        'set_term_encoding': policy_write_check_dict,
        'set_term_keyboard_mode': policy_write_check_dict,
        'swap_terminals': policy_write_check_dict,
        'move_terminal': policy_write_check_dict,
        'kill_terminal': policy_write_check_arg,
        'reset_terminal': policy_write_check_arg,
        'manual_title': policy_write_check_dict,
        'share_terminal': policy_share_terminal,
        'char_handler': policy_char_handler
    }
    auth_log = instance.ws.auth_log
    user = instance.current_user
    policy = applicable_policies('terminal', user, instance.ws.prefs)
    if not policy:  # Empty RUDict
        return True  # A world without limits!
    # Start by determining if the user can even login to the terminal app
    if 'allow' in policy:
        if not policy['allow']:
            auth_log.error(
                _("%s denied access to the Terminal application by policy." %
                  user['upn']))
            return False
    if function.__name__ in policy_functions:
        return policy_functions[function.__name__](cls, policy)
    return True  # Default to permissive if we made it this far
Beispiel #4
0
def terminal_policies(cls):
    """
    This function gets registered under 'terminal' in the
    :attr:`ApplicationWebSocket.security` dict and is called by the
    :func:`require` decorator by way of the :class:`policies` sub-function. It
    returns True or False depending on what is defined in the settings dir and
    what function is being called.

    This function will keep track of and place limmits on the following:

        * The number of open terminals.
        * How big each terminal may be.
        * Who may view or write to a shared terminal.

    If no 'terminal' policies are defined this function will always return True.
    """
    instance = cls.instance # TerminalApplication instance
    function = cls.function # Wrapped function
    #f_args = cls.f_args     # Wrapped function's arguments
    #f_kwargs = cls.f_kwargs # Wrapped function's keyword arguments
    policy_functions = {
        'new_terminal': policy_new_terminal,
        'resize': policy_write_check_dict,
        'set_term_encoding': policy_write_check_dict,
        'set_term_keyboard_mode': policy_write_check_dict,
        'move_terminal': policy_write_check_dict,
        'kill_terminal': policy_write_check_arg,
        'reset_terminal': policy_write_check_arg,
        'manual_title': policy_write_check_dict,
        'share_terminal': policy_share_terminal,
        'char_handler': policy_char_handler
    }
    auth_log = instance.ws.auth_log
    user = instance.current_user
    policy = applicable_policies('terminal', user, instance.ws.prefs)
    if not policy: # Empty RUDict
        return True # A world without limits!
    # Start by determining if the user can even login to the terminal app
    if 'allow' in policy:
        if not policy['allow']:
            auth_log.error(_(
                "%s denied access to the Terminal application by policy."
                % user['upn']))
            return False
    if function.__name__ in policy_functions:
        return policy_functions[function.__name__](cls, policy)
    return True # Default to permissive if we made it this far
Beispiel #5
0
def session_logging_check(self):
    """
    Attached to the `terminal:session_logging_check` WebSocket action; replies
    with `terminal:logging_sessions_disabled` if terminal session logging is
    disabled.

    .. note::

        The `terminal:logging_sessions_disabled` message just has the client
        remove the "Log Viewer" button so they don't get confused with an
        always-empty log viewer.
    """
    policy = applicable_policies('terminal', self.current_user, self.ws.prefs)
    session_logging = policy.get('session_logging', True)
    if not session_logging:
        message = {'terminal:logging_sessions_disabled': True}
        self.write_message(message)
Beispiel #6
0
def session_logging_check(self):
    """
    Attached to the `terminal:session_logging_check` WebSocket action; replies
    with `terminal:logging_sessions_disabled` if terminal session logging is
    disabled.

    .. note::

        The `terminal:logging_sessions_disabled` message just has the client
        remove the "Log Viewer" button so they don't get confused with an
        always-empty log viewer.
    """
    policy = applicable_policies(
        'terminal', self.current_user, self.ws.prefs)
    session_logging = policy.get('session_logging', True)
    if not session_logging:
        message = {'terminal:logging_sessions_disabled': True}
        self.write_message(message)
Beispiel #7
0
 def authenticate(self):
     """
     This gets called immediately after the user is authenticated
     successfully at the end of :meth:`ApplicationWebSocket.authenticate`.
     Sends all plugin JavaScript files to the client and triggers the
     'example:authenticate' event.
     """
     example_log.debug('ExampleApplication.authenticate()')
     # This is the log metadata that was mentioned near the top of this file.
     # This log_metadata will be JSON-encoded and included in all log
     # messages that use `self.example_log` which is super useful when
     # you need to parse logs at some later date and want to know the
     # circumstances surrounding any given message.
     self.log_metadata = {
         'upn': self.current_user['upn'],
         'ip_address': self.ws.request.remote_ip,
         # If your app uses the location feature make sure to include it:
         'location': self.ws.location
     }
     self.example_log = go_logger("gateone.example", **self.log_metadata)
     # NOTE:  To include even *more* metadata in a log message on a one-time
     # basis simply pass the metadata to the logger like so:
     #   self.example_log("Some log message", metadata={'foo': 'bar'})
     # That will ensure that {'foo': 'bar'} is included in the JSON portion
     # Assign our user-specific settings/policies for quick reference
     self.policy = applicable_policies(
         'example', self.current_user, self.ws.prefs)
     # NOTE:  The applicable_policies() function *is* memoized but the above
     #        is still much faster.
     # Start by determining if the user can even use this app
     if 'allow' in self.policy:
         # This is the same check inside example_policies().  Why put it here
         # too?  So we can skip sending the client JS/CSS that they won't be
         # able to use.
         if not self.policy['allow']:
             # User is not allowed to access this application.  Don't
             # bother sending them any static files and whatnot...
             self.example_log.debug(_(
                 "User is not allowed to use the Example application.  "
                 "Skipping post-authentication functions."))
             return
     # Render and send the client our example.css
     example_css = os.path.join(
         APPLICATION_PATH, 'templates', 'example.css')
     self.render_and_send_css(example_css, element_id="example.css")
     # NOTE:  See the Gate One docs for gateone.py to see how
     #        render_and_send_css() works.  It auto-minifies and caches!
     # Send the client our application's static JavaScript files
     static_dir = os.path.join(APPLICATION_PATH, 'static')
     js_files = []
     if os.path.isdir(static_dir):
         js_files = os.listdir(static_dir) # Everything in static/*.js
         js_files.sort()
     for fname in js_files:
         if fname.endswith('.js'):
             js_file_path = os.path.join(static_dir, fname)
             # This is notable:  To ensure that all your JavaScript files
             # get loaded *after* example.js we add 'example.js' as a
             # dependency for all JS files we send to the client.
             if fname == 'example.js':
                 # Adding CSS as a dependency to your app's JS is also a
                 # good idea.  You could also put 'theme.css' if you want to
                 # ensure that the theme gets loaded before your JavaScript
                 # init() function is called.
                 self.send_js(js_file_path, requires=["example.css"])
             else:
                 # Send any other discovered JS files to the client with
                 # example.js as the only dependency.
                 self.send_js(js_file_path, requires='example.js')
     # If you're not using plugins you can disregard this:
     # The send_plugin_static_files() function will locate any JS/CSS files
     # in your plugins' respective static directories and send them to the
     # client.  It is also smart enough to know which plugins are enabled
     # or disabled.
     self.ws.send_plugin_static_files(
         os.path.join(APPLICATION_PATH, 'plugins'),
         application="example",
         requires=["example.js"])
     sess = SESSIONS[self.ws.session] # A shortcut to save some typing
     # Create a place to store app-specific stuff related to this session
     # (but not necessarily this 'location')
     if "example" not in sess:
         sess['example'] = {} # A mostly persistent place to store info
     # If you want to call a function whenever Gate One exits just add it
     # to SESSIONS[self.ws.session]["kill_session_callbacks"] like so:
     #if kill_session_func not in sess["kill_session_callbacks"]:
         #sess["kill_session_callbacks"].append(kill_session_func)
     # If you want to call a function whenever a user's session times out
     # just attach it to SESSIONS[self.ws.session]["timeout_callbacks"]
     # like so:
     #if timeout_session_func not in sess["timeout_callbacks"]:
         #sess["timeout_callbacks"].append(timeout_session_func)
     # NOTE: The user will often be authenticated before example.js is
     # loaded.  In fact, the only time this won't be the case is when the
     # user is disconnected (e.g. server restart) and then reconnects.
     self.trigger("example:authenticate")
Beispiel #8
0
 def authenticate(self):
     """
     This gets called immediately after the user is authenticated
     successfully at the end of :meth:`ApplicationWebSocket.authenticate`.
     Sends all plugin JavaScript files to the client and triggers the
     'example:authenticate' event.
     """
     example_log.debug('ExampleApplication.authenticate()')
     # This is the log metadata that was mentioned near the top of this file.
     # This log_metadata will be JSON-encoded and included in all log
     # messages that use `self.example_log` which is super useful when
     # you need to parse logs at some later date and want to know the
     # circumstances surrounding any given message.
     self.log_metadata = {
         'upn': self.current_user['upn'],
         'ip_address': self.ws.request.remote_ip,
         # If your app uses the location feature make sure to include it:
         'location': self.ws.location
     }
     self.example_log = go_logger("gateone.example", **self.log_metadata)
     # NOTE:  To include even *more* metadata in a log message on a one-time
     # basis simply pass the metadata to the logger like so:
     #   self.example_log("Some log message", metadata={'foo': 'bar'})
     # That will ensure that {'foo': 'bar'} is included in the JSON portion
     # Assign our user-specific settings/policies for quick reference
     self.policy = applicable_policies('example', self.current_user,
                                       self.ws.prefs)
     # NOTE:  The applicable_policies() function *is* memoized but the above
     #        is still much faster.
     # Start by determining if the user can even use this app
     if 'allow' in self.policy:
         # This is the same check inside example_policies().  Why put it here
         # too?  So we can skip sending the client JS/CSS that they won't be
         # able to use.
         if not self.policy['allow']:
             # User is not allowed to access this application.  Don't
             # bother sending them any static files and whatnot...
             self.example_log.debug(
                 _("User is not allowed to use the Example application.  "
                   "Skipping post-authentication functions."))
             return
     # Render and send the client our example.css
     example_css = os.path.join(APPLICATION_PATH, 'templates',
                                'example.css')
     self.render_and_send_css(example_css, element_id="example.css")
     # NOTE:  See the Gate One docs for gateone.py to see how
     #        render_and_send_css() works.  It auto-minifies and caches!
     # Send the client our application's static JavaScript files
     static_dir = os.path.join(APPLICATION_PATH, 'static')
     js_files = []
     if os.path.isdir(static_dir):
         js_files = os.listdir(static_dir)  # Everything in static/*.js
         js_files.sort()
     for fname in js_files:
         if fname.endswith('.js'):
             js_file_path = os.path.join(static_dir, fname)
             # This is notable:  To ensure that all your JavaScript files
             # get loaded *after* example.js we add 'example.js' as a
             # dependency for all JS files we send to the client.
             if fname == 'example.js':
                 # Adding CSS as a dependency to your app's JS is also a
                 # good idea.  You could also put 'theme.css' if you want to
                 # ensure that the theme gets loaded before your JavaScript
                 # init() function is called.
                 self.send_js(js_file_path, requires=["example.css"])
             else:
                 # Send any other discovered JS files to the client with
                 # example.js as the only dependency.
                 self.send_js(js_file_path, requires='example.js')
     # If you're not using plugins you can disregard this:
     # The send_plugin_static_files() function will locate any JS/CSS files
     # in your plugins' respective static directories and send them to the
     # client.  It is also smart enough to know which plugins are enabled
     # or disabled.
     self.ws.send_plugin_static_files(os.path.join(APPLICATION_PATH,
                                                   'plugins'),
                                      application="example",
                                      requires=["example.js"])
     sess = SESSIONS[self.ws.session]  # A shortcut to save some typing
     # Create a place to store app-specific stuff related to this session
     # (but not necessarily this 'location')
     if "example" not in sess:
         sess['example'] = {}  # A mostly persistent place to store info
     # If you want to call a function whenever Gate One exits just add it
     # to SESSIONS[self.ws.session]["kill_session_callbacks"] like so:
     #if kill_session_func not in sess["kill_session_callbacks"]:
     #sess["kill_session_callbacks"].append(kill_session_func)
     # If you want to call a function whenever a user's session times out
     # just attach it to SESSIONS[self.ws.session]["timeout_callbacks"]
     # like so:
     #if timeout_session_func not in sess["timeout_callbacks"]:
     #sess["timeout_callbacks"].append(timeout_session_func)
     # NOTE: The user will often be authenticated before example.js is
     # loaded.  In fact, the only time this won't be the case is when the
     # user is disconnected (e.g. server restart) and then reconnects.
     self.trigger("example:authenticate")