| 1 | #!/usr/bin/env python |
|---|
| 2 | ############################################################################ |
|---|
| 3 | # |
|---|
| 4 | # DSAGE: Distributed SAGE |
|---|
| 5 | # |
|---|
| 6 | # Copyright (C) 2006, 2007 Yi Qiang <yqiang@gmail.com> |
|---|
| 7 | # |
|---|
| 8 | # Distributed under the terms of the GNU General Public License (GPL) |
|---|
| 9 | # |
|---|
| 10 | # This code is distributed in the hope that it will be useful, |
|---|
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 13 | # General Public License for more details. |
|---|
| 14 | # |
|---|
| 15 | # The full text of the GPL is available at: |
|---|
| 16 | # |
|---|
| 17 | # http://www.gnu.org/licenses/ |
|---|
| 18 | ############################################################################ |
|---|
| 19 | |
|---|
| 20 | import os |
|---|
| 21 | import random |
|---|
| 22 | import socket |
|---|
| 23 | import ConfigParser |
|---|
| 24 | import subprocess |
|---|
| 25 | import sys |
|---|
| 26 | |
|---|
| 27 | from sage.dsage.database.clientdb import ClientDatabase |
|---|
| 28 | from sage.dsage.misc.constants import DELIMITER as DELIMITER |
|---|
| 29 | from sage.dsage.misc.constants import DSAGE_DIR |
|---|
| 30 | from sage.dsage.misc.config import check_dsage_dir |
|---|
| 31 | from sage.dsage.__version__ import version |
|---|
| 32 | |
|---|
| 33 | from sage.misc.viewer import cmd_exists |
|---|
| 34 | |
|---|
| 35 | DB_DIR = os.path.join(DSAGE_DIR, 'db/') |
|---|
| 36 | SAGE_ROOT = os.getenv('SAGE_ROOT') |
|---|
| 37 | DSAGE_VERSION = version |
|---|
| 38 | |
|---|
| 39 | def get_config(type): |
|---|
| 40 | config = ConfigParser.ConfigParser() |
|---|
| 41 | config.add_section('general') |
|---|
| 42 | config.set('general', 'version', DSAGE_VERSION) |
|---|
| 43 | config.add_section('ssl') |
|---|
| 44 | if type == 'client': |
|---|
| 45 | config.add_section('auth') |
|---|
| 46 | config.add_section('log') |
|---|
| 47 | elif type == 'worker': |
|---|
| 48 | config.add_section('uuid') |
|---|
| 49 | config.add_section('log') |
|---|
| 50 | elif type == 'server': |
|---|
| 51 | config.add_section('auth') |
|---|
| 52 | config.add_section('server') |
|---|
| 53 | config.add_section('server_log') |
|---|
| 54 | config.add_section('db') |
|---|
| 55 | config.add_section('db_log') |
|---|
| 56 | return config |
|---|
| 57 | |
|---|
| 58 | def setup_client(testing=False): |
|---|
| 59 | check_dsage_dir() |
|---|
| 60 | key_file = os.path.join(DSAGE_DIR, 'dsage_key') |
|---|
| 61 | if testing: |
|---|
| 62 | cmd = ["ssh-keygen", "-q", "-trsa", "-P ''", "-f%s" % key_file] |
|---|
| 63 | return |
|---|
| 64 | |
|---|
| 65 | print DELIMITER |
|---|
| 66 | print "Generating public/private key pair for authentication..." |
|---|
| 67 | print "Your key will be stored in %s/dsage_key"%DSAGE_DIR |
|---|
| 68 | print "Just hit enter when prompted for a passphrase" |
|---|
| 69 | print DELIMITER |
|---|
| 70 | cmd = ["ssh-keygen", "-q", "-trsa", "-f%s" % key_file] |
|---|
| 71 | ld = os.environ['LD_LIBRARY_PATH'] |
|---|
| 72 | try: |
|---|
| 73 | del os.environ['LD_LIBRARY_PATH'] |
|---|
| 74 | p = subprocess.call(cmd) |
|---|
| 75 | finally: |
|---|
| 76 | os.environ['LD_LIBRARY_PATH'] = ld |
|---|
| 77 | print "\n" |
|---|
| 78 | print "Client configuration finished.\n" |
|---|
| 79 | |
|---|
| 80 | def setup_worker(): |
|---|
| 81 | check_dsage_dir() |
|---|
| 82 | print "Worker configuration finished.\n" |
|---|
| 83 | |
|---|
| 84 | def setup_server(template=None): |
|---|
| 85 | check_dsage_dir() |
|---|
| 86 | print "Choose a domain name for your SAGE notebook server," |
|---|
| 87 | print "for example, localhost (personal use) or %s (to allow outside connections)."%socket.getfqdn() |
|---|
| 88 | dn = raw_input("Domain name [localhost]: ").strip() |
|---|
| 89 | if dn == '': |
|---|
| 90 | print "Using default localhost" |
|---|
| 91 | dn = 'localhost' |
|---|
| 92 | |
|---|
| 93 | template_dict = {'organization': 'SAGE (at %s)'%(dn), |
|---|
| 94 | 'unit': '389', |
|---|
| 95 | 'locality': None, |
|---|
| 96 | 'state': 'Washington', |
|---|
| 97 | 'country': 'US', |
|---|
| 98 | 'cn': dn, |
|---|
| 99 | 'uid': 'sage_user', |
|---|
| 100 | 'dn_oid': None, |
|---|
| 101 | 'serial': str(random.randint(1,2**31)), |
|---|
| 102 | 'dns_name': None, |
|---|
| 103 | 'crl_dist_points': None, |
|---|
| 104 | 'ip_address': None, |
|---|
| 105 | 'expiration_days': 10000, |
|---|
| 106 | 'email': 'sage@sagemath.org', |
|---|
| 107 | 'ca': None, |
|---|
| 108 | 'tls_www_client': None, |
|---|
| 109 | 'tls_www_server': True, |
|---|
| 110 | 'signing_key': True, |
|---|
| 111 | 'encryption_key': True, |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | if isinstance(template, dict): |
|---|
| 115 | template_dict.update(template) |
|---|
| 116 | |
|---|
| 117 | s = "" |
|---|
| 118 | for key, val in template_dict.iteritems(): |
|---|
| 119 | if val is None: |
|---|
| 120 | continue |
|---|
| 121 | if val == True: |
|---|
| 122 | w = '' |
|---|
| 123 | elif isinstance(val, list): |
|---|
| 124 | w = ' '.join(['"%s"'%x for x in val]) |
|---|
| 125 | else: |
|---|
| 126 | w = '"%s"'%val |
|---|
| 127 | s += '%s = %s \n'%(key, w) |
|---|
| 128 | |
|---|
| 129 | template_file = os.path.join(DSAGE_DIR, 'cert.cfg') |
|---|
| 130 | f = open(template_file, 'w') |
|---|
| 131 | f.write(s) |
|---|
| 132 | f.close() |
|---|
| 133 | # Disable certificate generation -- not used right now anyways |
|---|
| 134 | privkey_file = os.path.join(DSAGE_DIR, 'cacert.pem') |
|---|
| 135 | pubkey_file = os.path.join(DSAGE_DIR, 'pubcert.pem') |
|---|
| 136 | print DELIMITER |
|---|
| 137 | print "Generating SSL certificate for server..." |
|---|
| 138 | if os.uname()[0] != 'Darwin' and cmd_exists('openssl'): |
|---|
| 139 | # We use openssl by default if it exists, since it is *vastly* |
|---|
| 140 | # faster on Linux. |
|---|
| 141 | cmd = ['openssl genrsa > %s' % privkey_file] |
|---|
| 142 | print "Using openssl to generate key" |
|---|
| 143 | print cmd[0] |
|---|
| 144 | subprocess.call(cmd, shell=True) |
|---|
| 145 | else: |
|---|
| 146 | cmd = ['certtool --generate-privkey --outfile %s' % privkey_file] |
|---|
| 147 | print "Using certtool to generate key" |
|---|
| 148 | print cmd[0] |
|---|
| 149 | # cmd = ['openssl genrsa > %s' % privkey_file] |
|---|
| 150 | subprocess.call(cmd, shell=True) |
|---|
| 151 | |
|---|
| 152 | # cmd = ['openssl req -config %s -new -x509 -key %s -out %s -days \ |
|---|
| 153 | # 1000' % (os.path.join(SAGE_ROOT,'local/openssl/openssl.cnf'), |
|---|
| 154 | # privkey_file, pubkey_file)] |
|---|
| 155 | cmd = ['certtool --generate-self-signed --template %s --load-privkey %s \ |
|---|
| 156 | --outfile %s' % (template_file, privkey_file, pubkey_file)] |
|---|
| 157 | subprocess.call(cmd, shell=True) |
|---|
| 158 | print DELIMITER |
|---|
| 159 | os.chmod(os.path.join(DSAGE_DIR, 'cacert.pem'), 0600) |
|---|
| 160 | |
|---|
| 161 | # conf_file = os.path.join(DSAGE_DIR, 'server.conf') |
|---|
| 162 | # config.write(open(conf_file, 'w')) |
|---|
| 163 | |
|---|
| 164 | # add default user |
|---|
| 165 | from twisted.conch.ssh import keys |
|---|
| 166 | import base64 |
|---|
| 167 | |
|---|
| 168 | # c = ConfigParser.ConfigParser() |
|---|
| 169 | # c.read(os.path.join(DSAGE_DIR, 'client.conf')) |
|---|
| 170 | from getpass import getuser |
|---|
| 171 | username = getuser() |
|---|
| 172 | pubkey_file = os.path.join(DSAGE_DIR, 'dsage_key.pub') |
|---|
| 173 | clientdb = ClientDatabase() |
|---|
| 174 | pubkey = base64.encodestring( |
|---|
| 175 | keys.getPublicKeyString(filename=pubkey_file).strip()) |
|---|
| 176 | if clientdb.get_user(username) is None: |
|---|
| 177 | clientdb.add_user(username, pubkey) |
|---|
| 178 | print 'Added user %s.\n' % (username) |
|---|
| 179 | else: |
|---|
| 180 | user, key = clientdb.get_user_and_key(username) |
|---|
| 181 | if key != pubkey: |
|---|
| 182 | clientdb.del_user(username) |
|---|
| 183 | clientdb.add_user(username, pubkey) |
|---|
| 184 | print "User %s's pubkey changed, setting to new one." % (username) |
|---|
| 185 | else: |
|---|
| 186 | print 'User %s already exists.' % (username) |
|---|
| 187 | |
|---|
| 188 | print "Server configuration finished.\n\n" |
|---|
| 189 | |
|---|
| 190 | def setup(template=None): |
|---|
| 191 | setup_client() |
|---|
| 192 | setup_worker() |
|---|
| 193 | setup_server(template=template) |
|---|
| 194 | print "Configuration finished.." |
|---|
| 195 | |
|---|
| 196 | if __name__ == '__main__': |
|---|
| 197 | if len(sys.argv) == 1: |
|---|
| 198 | setup() |
|---|
| 199 | if len(sys.argv) == 2: |
|---|
| 200 | if sys.argv[1] == 'server': |
|---|
| 201 | setup_server() |
|---|
| 202 | elif sys.argv[1] == 'worker': |
|---|
| 203 | setup_worker() |
|---|
| 204 | elif sys.argv[1] == 'client': |
|---|
| 205 | setup_client() |
|---|