forked from liftoff/GateOne
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Commit liftoff#1: The Gate One beta is about to go public.
- Loading branch information
0 parents
commit 04f2eab
Showing
170 changed files
with
35,150 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
COPYRIGHT NOTICE | ||
================ | ||
Gate One and all bundled original code... | ||
|
||
Copyright 2011 Liftoff Software Corporation | ||
|
||
Gate One is dual-licensed: AGPLv3 or Proprietary. | ||
|
||
Unless you have been granted a license from Liftoff Software, Gate One and all | ||
bundled software--except where noted--is licensed under the GNU Affero General | ||
Public License version 3. A copy of the AGPLv3 license should have been | ||
included with the Gate One software as AGPLv3.txt. If not, a copy may be | ||
obtained by visiting: | ||
|
||
http://www.gnu.org/licenses/agpl.html | ||
|
||
If the terms of the AGPLv3 license do not suit your needs, a proprietary | ||
license may be purchased from Liftoff Software: http://liftoffsoftware.com/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
Gate One is an HTML5 web-based terminal emulator and SSH client. Top features: | ||
|
||
* No browser plugins required! | ||
* Supports multiple simultaneous terminal sessions. As many as your | ||
hardware can handle. | ||
* Users can re-connect to their running terminals whenever they like from | ||
anywhere. | ||
* Can be embedded into other applications. Add a terminal--running whatever | ||
application(s) you want--to your web app! Would be vastly superior to | ||
say, a Java-based serial console applet (hint hint). | ||
* Includes powerful plugin system that supports plugins written in Python, | ||
JavaScript, and even CSS (yes, you can write a CSS-only plugin). | ||
* The Gate One server can be stopped & started without users losing their | ||
running terminal applications (even SSH sessions stay connected!). In | ||
essence, worry-free upgrades! | ||
* The SSH plugin allows users to duplicate sessions without having to | ||
re-enter their username and password (it re-uses the existing SSH tunnel). | ||
* Provides users with the ability to play back and save/share their terminal | ||
sessions via a self-contained HTML playback file. | ||
* Similarly, supports server-side logging, recording, and video-like | ||
playback of user sessions. It can even log to syslog to support | ||
whatever centralized logging system you want. | ||
* Keberos-based Single Sign-on support is included. It even works with | ||
Active Directory. Other authentication options are available as well. | ||
|
||
All documentation is in the "gateone/docs" directory. The HTML documentation is | ||
pre-built and ready-to-read. | ||
|
||
IMPORTANT: Gate One is currently IN BETA. Some things may be incomplete or | ||
buggy. Feel free to open new tickets in the issue tracker! | ||
|
||
FYI: Gate One was developed entirely by one guy in his spare time over the | ||
course of ~9 months. It turned out pretty good so he's looking to start a | ||
business out of it. What better way to create jobs than to start by creating | ||
one for yourself? All feedback, tips, and advice is appreciated: | ||
|
||
daniel.mcdougall@liftoffsoftware.com | ||
|
||
NOTE: http://liftoffsoftware.com/ hasn't been built yet so links pointing there | ||
will be dead for a while. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright 2011 Liftoff Software Corporation | ||
# | ||
|
||
# Meta | ||
__version__ = '0.9' | ||
__license__ = "AGPLv3 or Proprietary (see LICENSE.txt)" | ||
__version_info__ = (0, 9) | ||
__author__ = 'Dan McDougall <daniel.mcdougall@liftoffsoftware.com>' | ||
|
||
__doc__ = """\ | ||
Authentication | ||
============== | ||
This module contains Gate One's authentication classes. They map to Gate One's | ||
--auth configuration option like so: | ||
=============== =================== | ||
--auth=none NullAuthHandler | ||
--auth=kerberos KerberosAuthHandler | ||
--auth=google GoogleAuthHandler | ||
=============== =================== | ||
None or Anonymous | ||
----------------- | ||
By default Gate One will not authenticate users. This means that user sessions | ||
will be tied to their browser cookie and users will not be able to resume their | ||
sessions from another computer/browser. Most useful for situations where | ||
session persistence and logging aren't important. | ||
*All* users will show up as %anonymous using this authentication type. | ||
.. note:: The % is there to avoid name conflicts. | ||
Kerberos | ||
-------- | ||
Kerberos authentication utilizes GSSAPI for Single Sign-on (SSO) but will fall | ||
back to HTTP Basic authentication if GSSAPI auth fails. This authentication | ||
type can be integrated into any Kerberos infrastructure including Windows | ||
Active Directory. | ||
It is great for both transparent authentication and being able to tie sessions | ||
and logs to specific users within your organization (compliance). | ||
.. note:: The sso.py module itself has extensive documentation on this authentication type. | ||
Google Authentication | ||
--------------------- | ||
If you want persistent user sessions but don't care to run your own | ||
authentication infrastructure this authentication type is for you. Assuming, | ||
of course, that your Gate One server and clients will have access to the | ||
Internet. | ||
.. note:: This authentication type is perfect if you're using Chromebooks (Chrome OS devices). | ||
Docstrings | ||
========== | ||
""" | ||
|
||
# Import stdlib stuff | ||
import os | ||
import logging | ||
|
||
# Import our own stuff | ||
from utils import mkdir_p, generate_session_id | ||
|
||
# 3rd party imports | ||
import tornado.web | ||
import tornado.auth | ||
import tornado.escape | ||
|
||
class BaseAuthHandler(tornado.web.RequestHandler): | ||
"""The base class for all Gate One authentication handlers.""" | ||
def get_current_user(self): | ||
"""Tornado standard method--implemented our way.""" | ||
user_json = self.get_secure_cookie("user") | ||
if not user_json: return None | ||
return tornado.escape.json_decode(user_json) | ||
|
||
def user_login(self, user): | ||
""" | ||
Called immediately after a user authenticates successfully. Saves | ||
session information in the user's directory. Expects *user* to be a | ||
string containing the username or userPrincipalName. e.g. 'user@REALM' | ||
or just 'someuser'. | ||
""" | ||
# Make a directory to store this user's settings/files/logs/etc | ||
user_dir = self.settings['user_dir'] + "/" + user | ||
logging.info("Creating user directory: %s" % user_dir) | ||
mkdir_p(user_dir) | ||
os.chmod(user_dir, 0700) | ||
session_file = user_dir + '/session' | ||
if os.path.exists(session_file): | ||
session_data = open(session_file).read() | ||
session_info = tornado.escape.json_decode(session_data) | ||
else: | ||
with open(session_file, 'w') as f: | ||
# Save it so we can keep track across multiple clients | ||
session_info = { | ||
'go_upn': user, # FYI: UPN == userPrincipalName | ||
'go_session': generate_session_id() | ||
} | ||
session_info_json = tornado.escape.json_encode(session_info) | ||
f.write(session_info_json) | ||
self.set_secure_cookie("user", tornado.escape.json_encode(session_info)) | ||
|
||
def user_logout(self, user): | ||
""" | ||
Called immediately after a user logs out. Doesn't actually do | ||
anything. Just potential future use at this point. | ||
""" | ||
pass # Nothing here yet but someone might want to override it | ||
|
||
class NullAuthHandler(BaseAuthHandler): | ||
""" | ||
A handler for when no authentication method is chosen (i.e. --auth=none). | ||
""" | ||
def get(self): | ||
""" | ||
Sets the 'user' cookie with a new random session ID (*go_session*) and | ||
sets *go_upn* to '%anonymous'. | ||
""" | ||
# % is valid on the filesystem but invalid for an actual username. | ||
# This ensures we won't have a conflict at some point with an actual | ||
# user. | ||
user = r'%anonymous' | ||
self.user_login(user) # Takes care of the user's settings dir | ||
user_cookie = { | ||
'go_upn': user, | ||
'go_session': generate_session_id() | ||
} | ||
self.set_secure_cookie("user", tornado.escape.json_encode(user_cookie)) | ||
next_url = self.get_argument("next", None) | ||
if next_url: | ||
self.redirect(next_url) | ||
else: | ||
self.redirect("/") | ||
|
||
class GoogleAuthHandler(BaseAuthHandler, tornado.auth.GoogleMixin): | ||
""" | ||
Google authentication handler. | ||
""" | ||
@tornado.web.asynchronous | ||
def get(self): | ||
""" | ||
Sets the 'user' cookie with an appropriate *go_upn* and *go_session*. | ||
""" | ||
if self.get_argument("openid.mode", None): | ||
self.get_authenticated_user(self._on_auth) | ||
return | ||
self.authenticate_redirect( | ||
ax_attrs=["name","email","language","username"]) | ||
|
||
def _on_auth(self, user): | ||
""" | ||
Just a continuation of the get() method (the final step where it | ||
actually sets the cookie). | ||
""" | ||
if not user: | ||
raise tornado.web.HTTPError(500, "Google auth failed") | ||
print("GoogleAuthLoginHandler user: %s" % user) | ||
# NOTE: Google auth 'user' will be a dict like so: | ||
# user: { | ||
# 'locale': u'en-us', | ||
# 'first_name': u'Dan', | ||
# 'last_name': u'McDougall', | ||
# 'name': u'Dan McDougall', | ||
# 'email': u'riskable@gmail.com'} | ||
# Named these 'go_<whatever>' since that is less likely to conflict with | ||
# anything in the future (should some auth mechanism start returning | ||
# session IDs of some sort). | ||
self.user_login(user) # This takes care of the user's settings dir | ||
user_cookie = { # Don't need all that other stuff | ||
'go_session': generate_session_id(), | ||
'go_upn': user['email'] # Just an equivalent for standardization | ||
} | ||
self.set_secure_cookie("user", tornado.escape.json_encode(user_cookie)) | ||
next_url = self.get_argument("next", None) | ||
if next_url: | ||
self.redirect(next_url) | ||
else: | ||
self.redirect("/") | ||
|
||
# Add our KerberosAuthHandler if sso is available | ||
KerberosAuthHandler = None | ||
try: | ||
from sso import KerberosAuthMixin | ||
class KerberosAuthHandler(BaseAuthHandler, KerberosAuthMixin): | ||
""" | ||
Handles authenticating users via Kerberos/GSSAPI/SSO. | ||
""" | ||
def get(self): | ||
""" | ||
Checks the user's request header for the proper Authorization data. If | ||
it checks out the user will be logged in via _on_auth(). If not, the | ||
browser will be redirected to login. | ||
""" | ||
auth_header = self.request.headers.get('Authorization') | ||
if auth_header: | ||
self.get_authenticated_user(self._on_auth) | ||
return | ||
self.authenticate_redirect() | ||
|
||
def _on_auth(self, user): | ||
if not user: | ||
raise tornado.web.HTTPError(500, "Kerberos auth failed") | ||
self.user_login(user) # This takes care of the user's settings dir | ||
# TODO: Add some LDAP or local DB lookups here to add more detail to user objects | ||
logging.debug("KerberosAuthHandler user: %s" % user) | ||
next_url = self.get_argument("next", None) | ||
if next_url: | ||
self.redirect(next_url) | ||
else: | ||
self.redirect("/") | ||
except ImportError: | ||
pass # No SSO available. |
Oops, something went wrong.