Ejemplo n.º 1
0
def get_connect_string(self, term):
    """
    Attached to the (server-side) `terminal:ssh_get_connect_string` WebSocket
    action; writes the connection string associated with *term* to the WebSocket
    like so::

        {'terminal:sshjs_reconnect': {*term*: <connection string>}}

    In ssh.js we attach a WebSocket action to 'terminal:sshjs_reconnect'
    that assigns the connection string sent by this function to
    `GateOne.Terminal.terminals[*term*]['sshConnectString']`.
    """
    # This is the first function that normally gets called when a user uses SSH
    # so it's a good time to update the logger with extra metadata
    self.ssh_log = go_logger(
        "gateone.terminal.ssh", plugin='ssh', **self.log_metadata)
    term = int(term)
    if term not in self.loc_terms:
        return # Nothing to do (already closed)
    self.ssh_log.debug("get_connect_string()", metadata={'term': term})
    connect_string = self.loc_terms[term].get('ssh_connect_string', None)
    if connect_string:
        message = {
            'terminal:sshjs_reconnect': {
                'term': term,
                'connect_string': connect_string
            }
        }
        self.write_message(message)
Ejemplo n.º 2
0
def notice_esc_seq_handler(self, message, term=None, multiplex=None):
    """
    Handles text passed from the special optional escape sequance handler to
    display a *message* to the connected client (browser).  It can be invoked
    like so:

    .. ansi-block::

        $ echo -e "\033]_;notice|Text passed to some_function()\007"

    .. seealso::

        :class:`app_terminal.TerminalApplication.opt_esc_handler` and
        :func:`terminal.Terminal._opt_handler`
    """
    if not hasattr(self, 'notice_log'):
        self.notice_log = go_logger('gateone.terminal.notice',
                                    plugin='notice',
                                    **self.log_metadata)
    self.notice_log.info("Notice Plugin: %s" % message,
                         metadata={
                             'term': term,
                             'text': message
                         })
    message = "Term {term}: {message}".format(term=term, message=message)
    message = {'go:notice': message}
    self.write_message(message)
Ejemplo n.º 3
0
def initialize(self):
    """
    Called inside of :meth:`TerminalApplication.initialize` shortly after the
    WebSocket is instantiated.  Attaches our two `terminal:authenticate` events
    (to create the user's .ssh dir and send our CSS template) and ensures that
    the ssh_connect.py script is executable.
    """
    ssh_connect_path = os.path.join(PLUGIN_PATH, 'scripts', 'ssh_connect.py')
    if os.path.exists(ssh_connect_path):
        import stat
        st = os.stat(ssh_connect_path)
        if not bool(st.st_mode & stat.S_IXOTH):
            try:
                os.chmod(ssh_connect_path, 0o755)
            except OSError:
                ssh_log.error(_(
                    "Could not set %s as executable.  You will need to 'chmod "
                    "a+x' that script manually.") % ssh_connect_path)
                user_msg = _(
                    "Error loading SSH plugin:  The ssh_connect.py script is "
                    "not executable.  See the logs for more details.")
                send_msg = partial(self.ws.send_message, user_msg)
                events = ["terminal:authenticate", "terminal:new_terminal"]
                self.on(events, send_msg)
    self.ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh')
    # NOTE:  Why not use the 'Events' hook for these?  You can't attach two
    # functions to the same event via that mechanism because it's a dict
    # (one would override the other).
    # An alternative would be to write a single function say, on_auth() that
    # calls both of these functions then assign it to 'terminal:authenticate' in
    # the 'Events' hook.  I think this way is better since it is more explicit.
    self.on('terminal:authenticate', bind(send_ssh_css_template, self))
    self.on('terminal:authenticate', bind(create_user_ssh_dir, self))
Ejemplo n.º 4
0
def get_connect_string(self, term):
    """
    Attached to the (server-side) `terminal:ssh_get_connect_string` WebSocket
    action; writes the connection string associated with *term* to the WebSocket
    like so::

        {'terminal:sshjs_reconnect': {*term*: <connection string>}}

    In ssh.js we attach a WebSocket action to 'terminal:sshjs_reconnect'
    that assigns the connection string sent by this function to
    `GateOne.Terminal.terminals[*term*]['sshConnectString']`.
    """
    # This is the first function that normally gets called when a user uses SSH
    # so it's a good time to update the logger with extra metadata
    self.ssh_log = go_logger(
        "gateone.terminal.ssh", plugin='ssh', **self.log_metadata)
    term = int(term)
    if term not in self.loc_terms:
        return # Nothing to do (already closed)
    self.ssh_log.debug("get_connect_string()", metadata={'term': term})
    connect_string = self.loc_terms[term].get('ssh_connect_string', None)
    if connect_string:
        message = {
            'terminal:sshjs_reconnect': {
                'term': term,
                'connect_string': connect_string
            }
        }
        self.write_message(message)
Ejemplo n.º 5
0
def initialize(self):
    """
    Called inside of :meth:`TerminalApplication.initialize` shortly after the
    WebSocket is instantiated.  Attaches our two `terminal:authenticate` events
    (to create the user's .ssh dir and send our CSS template) and ensures that
    the ssh_connect.py script is executable.
    """
    ssh_connect_path = os.path.join(PLUGIN_PATH, 'scripts', 'ssh_connect.py')
    if os.path.exists(ssh_connect_path):
        import stat
        st = os.stat(ssh_connect_path)
        if not bool(st.st_mode & stat.S_IXOTH):
            try:
                os.chmod(ssh_connect_path, 0o755)
            except OSError:
                ssh_log.error(_(
                    "Could not set %s as executable.  You will need to 'chmod "
                    "a+x' that script manually.") % ssh_connect_path)
                user_msg = _(
                    "Error loading SSH plugin:  The ssh_connect.py script is "
                    "not executable.  See the logs for more details.")
                send_msg = partial(self.ws.send_message, user_msg)
                events = ["terminal:authenticate", "terminal:new_terminal"]
                self.on(events, send_msg)
    self.ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh')
    # NOTE:  Why not use the 'Events' hook for these?  You can't attach two
    # functions to the same event via that mechanism because it's a dict
    # (one would override the other).
    # An alternative would be to write a single function say, on_auth() that
    # calls both of these functions then assign it to 'terminal:authenticate' in
    # the 'Events' hook.  I think this way is better since it is more explicit.
    self.on('terminal:authenticate', bind(send_ssh_css_template, self))
    self.on('terminal:authenticate', bind(create_user_ssh_dir, self))
Ejemplo n.º 6
0
def initialize(self):
    """
    Called inside of :meth:`TerminalApplication.initialize` shortly after the
    WebSocket is instantiated.
    """
    self.ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh')
    # NOTE:  Why not use the 'Events' hook for these?  You can't attach two
    # functions to the same event via that mechanism because it's a dict
    # (one would override the other).
    # An alternative would be to write a single function say, on_auth() that
    # calls both of these functions then assign it to 'terminal:authenticate' in
    # the 'Events' hook.  I think this way is better since it is more explicit.
    self.on('terminal:authenticate', bind(send_ssh_css_template, self))
    self.on('terminal:authenticate', bind(create_user_ssh_dir, self))
Ejemplo n.º 7
0
def initialize(self):
    """
    Called inside of :meth:`TerminalApplication.initialize` shortly after the
    WebSocket is instantiated.  Attaches our two `terminal:authenticate` events
    (to create the user's .ssh dir and send our CSS template) and ensures that
    the ssh_connect.py script is executable.
    """
    ssh_connect_path = os.path.join(PLUGIN_PATH, 'scripts', 'ssh_connect.py')
    if os.path.exists(ssh_connect_path):
        import stat
        st = os.stat(ssh_connect_path)
        if not bool(st.st_mode & stat.S_IXOTH):
            os.chmod(ssh_connect_path, 0o755)
    self.ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh')
    # NOTE:  Why not use the 'Events' hook for these?  You can't attach two
    # functions to the same event via that mechanism because it's a dict
    # (one would override the other).
    # An alternative would be to write a single function say, on_auth() that
    # calls both of these functions then assign it to 'terminal:authenticate' in
    # the 'Events' hook.  I think this way is better since it is more explicit.
    self.on('terminal:authenticate', bind(send_ssh_css_template, self))
    self.on('terminal:authenticate', bind(create_user_ssh_dir, self))
Ejemplo n.º 8
0
def initialize(self):
    """
    Called inside of :meth:`TerminalApplication.initialize` shortly after the
    WebSocket is instantiated.  Attaches our two `terminal:authenticate` events
    (to create the user's .ssh dir and send our CSS template) and ensures that
    the ssh_connect.py script is executable.
    """
    ssh_connect_path = os.path.join(PLUGIN_PATH, 'scripts', 'ssh_connect.py')
    if os.path.exists(ssh_connect_path):
        import stat
        st = os.stat(ssh_connect_path)
        if not bool(st.st_mode & stat.S_IXOTH):
            os.chmod(ssh_connect_path, 0o755)
    self.ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh')
    # NOTE:  Why not use the 'Events' hook for these?  You can't attach two
    # functions to the same event via that mechanism because it's a dict
    # (one would override the other).
    # An alternative would be to write a single function say, on_auth() that
    # calls both of these functions then assign it to 'terminal:authenticate' in
    # the 'Events' hook.  I think this way is better since it is more explicit.
    self.on('terminal:authenticate', bind(send_ssh_css_template, self))
    self.on('terminal:authenticate', bind(create_user_ssh_dir, self))
Ejemplo n.º 9
0
def notice_esc_seq_handler(self, message, term=None, multiplex=None):
    """
    Handles text passed from the special optional escape sequance handler to
    display a *message* to the connected client (browser).  It can be invoked
    like so:

    .. ansi-block::

        $ echo -e "\033]_;notice|Text passed to some_function()\007"

    .. seealso::

        :class:`app_terminal.TerminalApplication.opt_esc_handler` and
        :func:`terminal.Terminal._opt_handler`
    """
    if not hasattr(self, 'notice_log'):
        self.notice_log = go_logger(
            'gateone.terminal.notice', plugin='notice', **self.log_metadata)
    self.notice_log.info(
        "Notice Plugin: %s" % message, metadata={'term': term, 'text': message})
    message = "Term {term}: {message}".format(term=term, message=message)
    message = {'go:notice': message}
    self.write_message(message)
Ejemplo n.º 10
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")
Ejemplo n.º 11
0
# gettext stuff if you want:
from gateone.core.locale import get_translation


# 3rd party imports
# You can add command line options to Gate One with define():
from tornado.options import define, options
# You need 'options' to get define()'d values

# Globals
SESSIONS = {} # This will get replaced with gateone.py's SESSIONS dict
# NOTE: The overwriting of SESSIONS happens inside of gateone.py as part of
# the application initialization process.
APPLICATION_PATH = os.path.split(__file__)[0] # Path to our application
web_handlers = [] # Populated at the bottom of this file
example_log = go_logger("gateone.example") # Our app's logger
# NOTE: You can pass additional metadata to logs which will be JSON-encoded
# when your messages are logged.  Examples of how to do this are further along
# in this file...

# Localization support
_ = get_translation() # You don't *have* to do this but it is a good idea

# This is how you add command-line options to Gate One:
define(
    "example_option", # NOTE: underscores are the preferred word separator here
    default=True,
    help=_("Doesn't do anything (just an example from the example app).")
)
# You could then reference this option like so:
# print(options.example_option)
# 3rd party imports
import tornado.web
import tornado.auth
import tornado.escape
import tornado.httpclient
import tornado.gen
from tornado.options import options

# Localization support
_ = get_translation()

# Globals
SETTINGS_CACHE = {}  # Lists of settings files and their modification times
# The security stuff below is a work-in-progress.  Likely to change all around.

auth_log = go_logger('gateone.auth')


# Helper functions
def additional_attributes(user, settings_dir=None):
    """
    Given a *user* dict, return a dict containing any additional attributes
    defined in Gate One's attribute repositories.

    .. note::

        This function doesn't actually work yet (support for attribute repos
        like LDAP is forthcoming).
    """
    # Doesn't do anything yet
    if not settings_dir:
Ejemplo n.º 13
0
__doc__ = """\
policy.py - A module containing the Terminal application's policy functions.
"""

# Meta
__license__ = "AGPLv3 or Proprietary (see LICENSE.txt)"
__author__ = 'Dan McDougall <*****@*****.**>'

from functools import partial
from gateone import SESSIONS
from gateone.core.locale import get_translation
from gateone.core.log import go_logger
from gateone.auth.authorization import applicable_policies

term_log = go_logger("gateone.terminal")

# Localization support
_ = get_translation()

def policy_new_terminal(cls, policy):
    """
    Called by :func:`terminal_policies`, returns True if the user is
    authorized to execute :func:`new_terminal` and applies any configured
    restrictions (e.g. max_dimensions).  Specifically, checks to make sure the
    user is not in violation of their applicable policies (e.g. max_terms).
    """
    instance = cls.instance
    session = instance.ws.session
    auth_log = instance.ws.auth_log
    try:
Ejemplo n.º 14
0
import os, sys, io, re, socket, tempfile, logging
from gateone import GATEONE_DIR
from .log import FACILITIES
from gateone.core.log import go_logger
from tornado import locale
from tornado.escape import json_decode
from tornado.options import define, options, Error

# Locale stuff (can't use .locale since .locale uses this module)
# Default to using the environment's locale with en_US fallback
temp_locale = locale.get(os.environ.get('LANG', 'en_US').split('.')[0])
_ = temp_locale.translate
del temp_locale

logger = go_logger(None)

class SettingsError(Exception):
    """
    Raised when we encounter an error parsing .conf files in the settings dir.
    """
    pass

class RUDict(dict):
    """
    A dict that will recursively update keys and values in a safe manner so that
    sub-dicts will be merged without one clobbering the other.

    .. note::

        This class (mostly) taken from `here
Ejemplo n.º 15
0
# 3rd party imports
import tornado.web
import tornado.auth
import tornado.escape
import tornado.httpclient
import tornado.gen
from tornado.options import options

# Localization support
_ = get_translation()

# Globals
SETTINGS_CACHE = {}  # Lists of settings files and their modification times
# The security stuff below is a work-in-progress.  Likely to change all around.

auth_log = go_logger("gateone.auth")

# Helper functions
def additional_attributes(user, settings_dir=None):
    """
    Given a *user* dict, return a dict containing any additional attributes
    defined in Gate One's attribute repositories.

    .. note::

        This function doesn't actually work yet (support for attribute repos
        like LDAP is forthcoming).
    """
    # Doesn't do anything yet
    if not settings_dir:
        settings_dir = options.settings_dir
Ejemplo n.º 16
0
__version_info__ = (1, 0)
__author__ = 'Stuart Johnson <*****@*****.**>'

import os
import threading
from gateone.core.server import BaseHandler
import tornado.escape
import tornado.web
from subprocess import call
import datetime
from gateone.core.log import go_logger
import glob

# Globals
PLUGIN_PATH = os.path.split(__file__)[0]  # Path to our plugin's directory
ssh_log = go_logger("gateone.terminal.revssh", plugin='revssh')

connectFilename = "connect.sh"
infoFilename = "info.html"

portCounterMin = 10000
portCounterMax = 19999
portCounter = portCounterMin
portCounterLock = threading.Lock()
RSAPathPrefix = "/tmp/rsa_"
sshpyPath = "/home/admin/ssh.py"

with open('/home/admin/.ssh/id_rsa.pub', 'r') as f:
    rsapub = f.read().rstrip()

sshPort = os.environ['SSHPORT']
Ejemplo n.º 17
0
import os, sys, io, re, socket, tempfile, logging
from gateone import GATEONE_DIR
from .log import FACILITIES
from gateone.core.log import go_logger
from tornado import locale
from tornado.escape import json_decode
from tornado.options import define, options, Error

# Locale stuff (can't use .locale since .locale uses this module)
# Default to using the environment's locale with en_US fallback
temp_locale = locale.get(os.environ.get('LANG', 'en_US').split('.')[0])
_ = temp_locale.translate
del temp_locale

logger = go_logger(None)
comments_re = re.compile(
    r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
    re.DOTALL | re.MULTILINE)
trailing_commas_re = re.compile(
    r'(,)\s*}(?=([^"\\]*(\\.|"([^"\\]*\\.)*[^"\\]*"))*[^"]*$)')


class SettingsError(Exception):
    """
    Raised when we encounter an error parsing .conf files in the settings dir.
    """
    pass


class RUDict(dict):
Ejemplo n.º 18
0
# You can use this for providing localization but you could just use the stdlib
# gettext stuff if you want:
from gateone.core.locale import get_translation

# 3rd party imports
# You can add command line options to Gate One with define():
from tornado.options import define, options
# You need 'options' to get define()'d values

# Globals
SESSIONS = {}  # This will get replaced with gateone.py's SESSIONS dict
# NOTE: The overwriting of SESSIONS happens inside of gateone.py as part of
# the application initialization process.
APPLICATION_PATH = os.path.split(__file__)[0]  # Path to our application
web_handlers = []  # Populated at the bottom of this file
example_log = go_logger("gateone.example")  # Our app's logger
# NOTE: You can pass additional metadata to logs which will be JSON-encoded
# when your messages are logged.  Examples of how to do this are further along
# in this file...

# Localization support
_ = get_translation()  # You don't *have* to do this but it is a good idea

# This is how you add command-line options to Gate One:
define(
    "example_option",  # NOTE: underscores are the preferred word separator here
    default=True,
    help=_("Doesn't do anything (just an example from the example app)."))
# You could then reference this option like so:
# print(options.example_option)
Ejemplo n.º 19
0
# Standard library imports
import os, io

# Gate One imports
from gateone.core.utils import json_encode
from gateone.core.configuration import RUDict
from gateone.core.locale import get_translation
from gateone.core.log import go_logger

# 3rd party imports
from tornado.escape import json_decode
from tornado.options import options

APPLICATION_PATH = os.path.split(__file__)[0]  # Path to our application
term_log = go_logger("gateone.terminal")

# Localization support
_ = get_translation()


def save_term_settings(term, location, session, settings):
    """
    Saves the *settings* associated with the given *term*, *location*, and
    *session* in the 'term_settings.json' file inside the user's session
    directory.

    When complete the given *callback* will be called (if given).
    """
    if not session:
        return  # Just a viewer of a broadcast terminal
Ejemplo n.º 20
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")
Ejemplo n.º 21
0
from gateone.core.log import go_logger

# 3rd party imports
import tornado.web
import tornado.auth
import tornado.escape

# Localization support
_ = get_translation()

# Globals
GATEONE_DIR = os.path.dirname(os.path.abspath(__file__))
SETTINGS_CACHE = {} # Lists of settings files and their modification times
# The security stuff below is a work-in-progress.  Likely to change all around.

auth_log = go_logger('gateone.auth')

# Helper functions
def additional_attributes(user, settings_dir=None):
    """
    Given a *user* dict, return a dict containing any additional attributes
    defined in Gate One's attribute repositories.

    .. note::

        This function doesn't actually work yet (support for attribute repos
        like LDAP is forthcoming).
    """
    # Doesn't do anything yet
    if not settings_dir:
        settings_dir = os.path.join(GATEONE_DIR, 'settings')
Ejemplo n.º 22
0
# Our stuff
from gateone.core.server import BaseHandler
from gateone.core.utils import mkdir_p, shell_command, which
from gateone.core.utils import noop, bind
from gateone.core.locale import get_translation
from gateone.core.log import go_logger

_ = get_translation()

# Tornado stuff
import tornado.web
import tornado.ioloop

# Globals
ssh_log = go_logger("gateone.terminal.ssh", plugin='ssh')
OPENSSH_VERSION = None
DROPBEAR_VERSION = None
PLUGIN_PATH = os.path.split(__file__)[0] # Path to this plugin's directory
OPEN_SUBCHANNELS = {}
SUBCHANNEL_TIMEOUT = timedelta(minutes=5) # How long to wait before auto-closing
READY_STRING = "GATEONE_SSH_EXEC_CMD_CHANNEL_READY"
READY_MATCH = re.compile("^%s$" % READY_STRING, re.MULTILINE)
OUTPUT_MATCH = re.compile(
    "^{rs}.+^{rs}$".format(rs=READY_STRING), re.MULTILINE|re.DOTALL)
VALID_PRIVATE_KEY = valid = re.compile(
    r'^-----BEGIN [A-Z]+ PRIVATE KEY-----.*-----END [A-Z]+ PRIVATE KEY-----$',
    re.MULTILINE|re.DOTALL)
TIMER = None # Used to store temporary, cancellable timeouts
# TODO: make execute_command() a user-configurable option...  So it will automatically run whatever command(s) the user likes whenever they connect to a given server.  Differentiate between when they connect and when they start up a master or slave channel.
# TODO: Make it so that equivalent KnownHostsHandler functionality works over the WebSocket.