Compare commits

...

73 commits

Author SHA1 Message Date
Jakobus Schürz 4bb3c5f107 change logging format for python 3 2021-10-31 12:12:59 +01:00
Jakobus Schürz 0934212421 change lineend for authorized_keys 2021-10-31 12:07:57 +01:00
Jakobus Schürz f839d08232 change description of repositories 2021-10-31 12:02:28 +01:00
Jakobus Schürz daadb52b9c change print for python3 2021-10-31 11:58:12 +01:00
Jakobus Schürz a6205344b1 fix _levelNames error 2021-10-02 20:08:52 +02:00
Jakobus Schürz 1504a33496 Python 3 2021-10-02 19:50:36 +02:00
Jakobus Schürz 74adca7e7e Merge remote-tracking branch 'mgukov/master' 2021-10-02 19:41:20 +02:00
Jakobus Schürz b005b18e89 Merge branch 'principals-with-host' 2019-10-29 11:25:50 +01:00
Jakobus Schürz 89921e7838 fix improved logging 2019-09-06 00:56:39 +02:00
Jakobus Schürz ebaf7a7f71 improve debug 2019-09-06 00:55:38 +02:00
Jakobus Schürz 0fe0eef34d debug added 2019-09-06 00:52:33 +02:00
Jakobus Schürz 2cb9ed308a remove debug-log 2019-09-06 00:44:26 +02:00
Jakobus Schürz ea02faf354 fixed logging when GIT_DIR is none 2019-09-06 00:38:07 +02:00
Jakobus Schürz 98be92f149 debug 2019-09-06 00:35:17 +02:00
Jakobus Schürz 9defb275d3 fix logging if GIT_DIR is none 2019-09-06 00:23:52 +02:00
Jakobus Schürz 2039e7fb10 Add sshd_config snippet for users not git
Added another snippet for sshd_config to use principal-files for users
which are NOT git. There you can also use another
AuthorizedPrincipalsCommand, if you want instead.
2019-08-28 09:17:18 +02:00
Jakobus Schürz 8fbf51be7a yield changed to print 2019-08-04 03:09:47 +02:00
Jakobus Schürz 2c7b1c6e22 print removed 2019-08-04 03:08:22 +02:00
Jakobus Schürz e15bad3da1 only build principal with username out of user@host
yield principals instead of print
2019-08-04 02:52:44 +02:00
Jakobus Schürz 34e373864f log entfernt 2019-08-03 15:28:56 +02:00
Jakobus Schürz 1a02e0763e debug 2019-08-03 15:27:54 +02:00
Jakobus Schürz 26e6fc448c split output 2019-08-03 15:26:17 +02:00
Jakobus Schürz 6c2c4ecd6d list as input for loop 2019-08-03 15:24:37 +02:00
Jakobus Schürz 174de200c5 debugging 2019-08-03 15:23:41 +02:00
Jakobus Schürz 458e7e2a09 variable renamed 2019-08-03 15:22:32 +02:00
Jakobus Schürz 64b3391498 a line for each principal 2019-08-03 15:21:13 +02:00
Jakobus Schürz 55b54aed64 return added 2019-08-03 15:15:39 +02:00
Jakobus Schürz 4d1775f258 debuglog 2019-08-03 15:09:35 +02:00
Jakobus Schürz 87ece5e9e6 principals added 2019-08-02 16:40:56 +02:00
Jakobus Schürz 732f818f8b principals added to example.conf 2019-08-02 10:05:24 +02:00
Jakobus Schürz fb0fdf2111 Initialisation with principals added 2019-08-02 10:00:32 +02:00
Jakobus Schürz be752d3808 Formatting fixed (h2 instead of h3) 2019-08-02 09:54:21 +02:00
Jakobus Schürz bad18e8fc4 Formatting h3 tryout 2019-08-02 09:52:57 +02:00
Jakobus Schürz a0e4459423 static principal-files removed, also from README 2019-08-02 09:38:28 +02:00
Jakobus Schürz cc9f200554 Readme ergänzt 2019-08-02 03:54:56 +02:00
Jakobus Schürz 96c6226f7e dependency added 2019-08-02 03:45:51 +02:00
Jakobus Schürz de80f5c9e9 users in static principal-files 2019-08-02 03:43:25 +02:00
Jakobus Schürz 2a528be734 readme static principal-files added 2019-08-02 03:26:48 +02:00
Jakobus Schürz fb9da76837 only key ID from ssh-certificate is used 2019-08-02 03:17:32 +02:00
Jakobus Schürz b8fee87586 contact added 2019-08-02 03:09:47 +02:00
Jakobus Schürz 6f5727f25b formatierung changed 2019-08-02 03:07:49 +02:00
Jakobus Schürz acc17bccc8 Use of principals added to README 2019-08-02 03:02:25 +02:00
Jakobus Schürz 3f9ba857d3 long username removed 2019-08-02 02:07:30 +02:00
Jakobus Schürz 648319b634 path durch principals ersetzt 2019-08-02 01:50:54 +02:00
Jakobus Schürz a96ad0df9d git_dir check removed 2019-08-02 01:49:16 +02:00
Jakobus Schürz e6691d2c49 git_dir removed 2019-08-02 01:47:53 +02:00
Jakobus Schürz ca4479cdc0 Where comes GIT_DIR from? 2019-08-02 01:36:36 +02:00
Jakobus Schürz 490c089f1e missing code added 2019-08-02 01:06:19 +02:00
Jakobus Schürz 42c5352406 util fixed 2019-08-02 01:02:21 +02:00
Jakobus Schürz 9d50d26912 fixed 2019-08-02 01:01:23 +02:00
Jakobus Schürz 4497a2b71e getAllowedSSHPrincipals from config 2019-08-02 00:58:21 +02:00
Jakobus Schürz 46278d689f logfile 2019-08-02 00:12:22 +02:00
Jakobus Schürz 3442e2ef3b logfile in home fixed 2019-08-02 00:03:22 +02:00
Jakobus Schürz 6487465d74 logging entfernt 2019-08-02 00:02:16 +02:00
Jakobus Schürz 5796ba441d logfile in ~ 2019-08-02 00:01:04 +02:00
Jakobus Schürz 1fc6d57c0d log to logifile 2019-08-01 23:10:32 +02:00
Jakobus Schürz 7438aedf64 added logfile 2019-08-01 23:08:54 +02:00
Jakobus Schürz de05ba9144 loop fixed 2019-08-01 22:54:42 +02:00
Jakobus Schürz 3d479977f0 sshUser mit und ohne @ 2019-08-01 22:52:35 +02:00
Jakobus Schürz 544a26c54a user->sshUser 2019-08-01 22:46:05 +02:00
Jakobus Schürz e2302c25bf log removed 2019-08-01 22:45:22 +02:00
Jakobus Schürz efdab87466 loop removed 2019-08-01 22:44:42 +02:00
Jakobus Schürz ba197a1ea7 print line 2019-08-01 22:43:25 +02:00
Jakobus Schürz 0d631132e0 debug 2019-08-01 22:41:53 +02:00
Jakobus Schürz b88948bb2c debug 2019-08-01 22:34:11 +02:00
Jakobus Schürz 9b3b7ae6c2 debug 2019-08-01 22:29:29 +02:00
Jakobus Schürz 7d993c0b10 debug 2019-08-01 22:27:28 +02:00
Jakobus Schürz 60cf43a0db typo fixed 2019-08-01 20:59:17 +02:00
Jakobus Schürz 2b9038c797 typo fixed 2019-08-01 20:58:05 +02:00
Jakobus Schürz bd57935d6e First step AuthorizedPrincipalCommand added 2019-08-01 17:50:55 +02:00
Michael Gukov a5c8c2022b Python3 2018-12-17 01:47:01 +05:00
Michael 35a9a8a8ba Python3 2018-12-17 00:38:12 +05:00
Michael aca25db85d Python 3 2018-12-11 12:38:41 +05:00
28 changed files with 242 additions and 169 deletions

2
.gitignore vendored
View file

@ -5,3 +5,5 @@
/apidocs
/gitosis/test/tmp
/.coverage
.idea
venv

View file

@ -24,7 +24,17 @@ more information.
You can get ``gitosis`` via ``git`` by saying::
git clone https://github.com/tv42/gitosis.git
This repositories are from jakob@schuerz.at, support python3 and ssh-certificates
git clone git@codeberg.org:xundeenergie/gitosis.git (fetch)
git clone git@github.com:xundeenergie/gitosis.git (fetch)
git clone git@git.schuerz.at:public/gitosis.git (fetch)
This repository translates gitosis to python3, but not fully.
git clone git@github.com:mgukov/gitosis.git (push)
Original repository seems unmaintained
git clone git@github.com:tv42/gitosis.git (fetch)
And install it via::
@ -75,6 +85,12 @@ it to running ``gitosis-serve``. Run::
sudo -H -u git gitosis-init <FILENAME.pub
# (or just copy-paste the public key when prompted)
If you want to use ssh-certificates with principals, you need a file with
your admin-user in it. Name it adminuser.txt, only one line with your admins
username in it and run::
sudo -H -u git gitosis-init <adminuser.txt
then just ``git clone git@SERVER:gitosis-admin.git``, and you get a
repository with SSH keys as ``keys/USER.pub`` and a ``gitosis.conf``
where you can configure who has access to what.
@ -190,6 +206,75 @@ Note that this short snippet is not a substitute for reading and
understanding the relevant documentation.
Using ssh-certificates and principals
=====================================
``ssh certificates`` are a new feature of openssh, where you setup your own ssh-CA
and you sign all you host- and user-pubkeys.
If you want to use certificates ans principals, please visit THIS_ and THIS_ website.
To find out more about the AuthorizedPrincipalCommand in sshd_config, please consult GITLABS_
documentation for it.
.. _THIS: https://ef.gy/hardening-ssh
.. _THIS: https://framkant.org/2017/07/scalable-access-control-using-openssh-certificates/
.. _GITLABS: https://docs.gitlab.com/ee/administration/operations/ssh_certificates.html
To use principals and ssh-certificates with this fork of gitosis, please add this snippet to your sshd_config on your git-server::
Match User git
AuthorizedPrincipalsCommandUser git
AuthorizedPrincipalsCommand /usr/local/bin/gitosis-authorized-principals %i
And for all users except git, use only principal-files::
Match User !git,*
AuthorizedPrincipalsFile /etc/ssh/userprincipals/%u
This will run the command as user "git", which will you have installed, when you serve your gitrepos with gitosis.
%i is the key-identity of your certificate, which will you give on your sign-process to the user-certificate.
Then you need an additional line in your gitosis.conf in the [gitosis]-section::
[gitosis]
...
allowedPrincipals = git gitosis-admin
In the members-line of your gitosis.conf, you have to write down the key-identity (which is passed as %i in you sshd_config). If you are not sure,
what the identity is, try::
ssh-keygen -L -f ~/.ssh/id_rsa-cert.pub
/home/myusername/.ssh/id_rsa-cert.pub:
Type: ssh-rsa-cert-v01@openssh.com user certificate
Public key: RSA-CERT SHA256:cjLH4l45G32zOaJBjv8Udnr7bkwHRNB3nAz0a6SCOl0
Signing CA: ED25519 SHA256:9bMENs+blen§naslr§BJEN421I5ckbu4mvpnktiHdUs (using ssh-ed25519)
Key ID: "myusername"
Serial: 4
Valid: from 2019-08-02T02:29:00 to 2020-08-01T02:30:20
Principals:
myusername
principal2
git
gitosis-admin
Critical Options: (none)
Extensions:
permit-X11-forwarding
permit-agent-forwarding
permit-port-forwarding
permit-pty
permit-user-rc
from your principals in the key, only git and gitosis-admin are allowed. You must have at least one of this allowed principals in your key, to get access to your gitosis-served repos.
Access is only given, if you have one of the allowed principals in your certificate, and your key ID is listed as member in the repo
Parallel use of principals/certificates an pubkeys
--------------------------------------------------
It is possible, to use pubkeys in parallel to these principals from certificates. Just as described above. If you have a user, which has no certificate from your ssh-CA, just add his
public-sshkey in the keydir. (not tested now)
Contact
=======
@ -197,5 +282,7 @@ Contact
You can email the author at ``tv@eagain.net``, or hop on
``irc.freenode.net`` channel ``#git`` and hope for the best.
For ssh-certificates and principals, please contact wertstoffe@xundeenergie.at
There will be more, keep an eye on http://eagain.net/ and/or the git
mailing list.

View file

@ -40,9 +40,9 @@
- can't trust "~"::
[0 tv@musti ~]$ sudo python -c 'import os; print os.path.expanduser("~")'
[0 tv@musti ~]$ sudo python -c 'import os; print(os.path.expanduser("~"))'
/home/tv
[0 tv@musti ~]$ sudo -H python -c 'import os; print os.path.expanduser("~")'
[0 tv@musti ~]$ sudo -H python -c 'import os; print(os.path.expanduser("~"))'
/root
- command line options

View file

@ -18,6 +18,12 @@ daemon = no
## Logging level, one of DEBUG, INFO, WARNING, ERROR, CRITICAL
loglevel = DEBUG
## If you use ssh-certificates with principals, you need this option
## If commented, allowedPrincipals defaults to "git". At least, your certificates of the users
## which want to use this repos, must have at least "git" as principal in their
## certificates
allowedPrincipals = git
[group quux]
members = jdoe wsmith @anothergroup
writable = foo bar baz/thud

View file

@ -1,5 +1,5 @@
import os, logging
from ConfigParser import NoSectionError, NoOptionError
from configparser import NoSectionError, NoOptionError
from gitosis import group

View file

@ -3,7 +3,7 @@ import sys
import logging
import optparse
import errno
import ConfigParser
import configparser
log = logging.getLogger('gitosis.app')
@ -31,14 +31,14 @@ class App(object):
cfg = self.create_config(options)
try:
self.read_config(options, cfg)
except CannotReadConfigError, e:
except CannotReadConfigError as e:
log.error(str(e))
sys.exit(1)
self.setup_logging(cfg)
self.handle_args(parser, cfg, options, args)
def setup_basic_logging(self):
logging.basicConfig(filename='gitosis.log', level=10)
logging.basicConfig(filename='/home/git/gitosis.log')
def create_parser(self):
parser = optparse.OptionParser()
@ -53,13 +53,13 @@ class App(object):
return parser
def create_config(self, options):
cfg = ConfigParser.RawConfigParser()
cfg = configparser.RawConfigParser()
return cfg
def read_config(self, options, cfg):
try:
conffile = file(options.config)
except (IOError, OSError), e:
conffile = open(options.config)
except (IOError, OSError) as e:
if e.errno == errno.ENOENT:
# special case this because gitosis-init wants to
# ignore this particular error case
@ -74,12 +74,12 @@ class App(object):
def setup_logging(self, cfg):
try:
loglevel = cfg.get('gitosis', 'loglevel')
except (ConfigParser.NoSectionError,
ConfigParser.NoOptionError):
except (configparser.NoSectionError,
configparser.NoOptionError):
pass
else:
try:
symbolic = logging._levelNames[loglevel]
symbolic = logging._nameToLevel[loglevel]
except KeyError:
log.warning(
'Ignored invalid loglevel configuration: %r',

View file

@ -2,7 +2,7 @@ import errno
import logging
import os
from ConfigParser import NoSectionError, NoOptionError
from configparser import NoSectionError, NoOptionError
log = logging.getLogger('gitosis.gitdaemon')
@ -14,13 +14,13 @@ def export_ok_path(repopath):
def allow_export(repopath):
p = export_ok_path(repopath)
file(p, 'a').close()
open(p, 'a').close()
def deny_export(repopath):
p = export_ok_path(repopath)
try:
os.unlink(p)
except OSError, e:
except OSError as e:
if e.errno == errno.ENOENT:
pass
else:

View file

@ -27,7 +27,7 @@ To plug this into ``gitweb``, you have two choices.
import os, urllib, logging
from ConfigParser import NoSectionError, NoOptionError
from configparser import NoSectionError, NoOptionError
from gitosis import util
@ -91,8 +91,9 @@ def generate_project_list_fp(config, fp):
else:
response.append(owner)
line = ' '.join([urllib.quote_plus(s) for s in response])
print >>fp, line
line = ' '.join([urllib.parse.quote_plus(s) for s in response])
#print >>fp, line
print(line, end="", file=fp)
def generate_project_list(config, path):
"""
@ -106,7 +107,7 @@ def generate_project_list(config, path):
"""
tmp = '%s.%d.tmp' % (path, os.getpid())
f = file(tmp, 'w')
f = open(tmp, 'w')
try:
generate_project_list_fp(config=config, fp=f)
finally:
@ -157,9 +158,10 @@ def set_descriptions(config):
'description',
)
tmp = '%s.%d.tmp' % (path, os.getpid())
f = file(tmp, 'w')
f = open(tmp, 'w')
try:
print >>f, description
#print >>f, description
print(description, end="", file=f)
finally:
f.close()
os.rename(tmp, path)

View file

@ -1,5 +1,5 @@
import logging
from ConfigParser import NoSectionError, NoOptionError
from configparser import NoSectionError, NoOptionError
def _getMembership(config, user, seen):
log = logging.getLogger('gitosis.group.getMembership')

View file

@ -9,8 +9,8 @@ import sys
import re
from pkg_resources import resource_filename
from cStringIO import StringIO
from ConfigParser import RawConfigParser
from io import StringIO
from configparser import RawConfigParser
from gitosis import repository
from gitosis import run_hook
@ -68,7 +68,7 @@ def symlink_config(git_dir):
tmp = '%s.%d.tmp' % (dst, os.getpid())
try:
os.unlink(tmp)
except OSError, e:
except OSError as e:
if e.errno == errno.ENOENT:
pass
else:
@ -94,15 +94,18 @@ def init_admin_repository(
# can't rely on setuptools and all kinds of distro packaging to
# have kept our templates executable, it seems
os.chmod(os.path.join(git_dir, 'hooks', 'post-update'), 0755)
os.chmod(os.path.join(git_dir, 'hooks', 'post-update'), 0o755)
if not repository.has_initial_commit(git_dir):
log.info('Making initial commit...')
# ConfigParser does not guarantee order, so jump through hoops
# to make sure [gitosis] is first
cfg_file = StringIO()
print >>cfg_file, '[gitosis]'
print >>cfg_file
print('[gitosis]', file=cfg_file)
#print('', end="", file=cfg_file)
#print >>cfg_file, '[gitosis]'
#print >>cfg_file
cfg = RawConfigParser()
cfg.add_section('group gitosis-admin')
cfg.set('group gitosis-admin', 'members', user)
@ -133,7 +136,7 @@ class Main(app.App):
def handle_args(self, parser, cfg, options, args):
super(Main, self).handle_args(parser, cfg, options, args)
os.umask(0022)
os.umask(0o022)
log.info('Reading SSH public key...')
pubkey = read_ssh_pubkey()
@ -158,7 +161,7 @@ class Main(app.App):
user=user,
)
log.info('Running post-update hook...')
util.mkdir(os.path.expanduser('~/.ssh'), 0700)
util.mkdir(os.path.expanduser('~/.ssh'), 0o700)
run_hook.post_update(cfg=cfg, git_dir=admin_repository)
log.info('Symlinking ~/.gitosis.conf to repository...')
symlink_config(git_dir=admin_repository)

48
gitosis/principals.py Normal file
View file

@ -0,0 +1,48 @@
"""
Perform gitosis actions for a git hook.
"""
import errno
import logging
import os
import sys
import shutil
from gitosis import repository
from gitosis import ssh
from gitosis import gitweb
from gitosis import gitdaemon
from gitosis import app
from gitosis import util
def serve_principal(cfg, sshUser, principals):
TEMPLATE=('command="gitosis-serve %(user)s",no-port-forwarding,'
+'no-X11-forwarding,no-agent-forwarding,no-pty %(principals)s')
for p in util.getAllowedSSHPrincipals(config=cfg).split() :
print(TEMPLATE % dict(user=sshUser.partition('@')[0], principals=p))
class Main(app.App):
def create_parser(self):
parser = super(Main, self).create_parser()
parser.set_usage('%prog [OPTS] sshUser principal principal ...')
parser.set_description(
'Serves principals as AuthorizedPrincipalsCommand ')
return parser
def handle_args(self, parser, cfg, options, args):
try:
sshUser = args.pop(0)
principals = ' '.join(args)
except ValueError:
parser.error('Missing argument sshUsers and/or principals.')
log = logging.getLogger('gitosis.principals')
if sshUser != "":
log.info('Running serve_principal for user %s', sshUser)
#log.debug('serve_principal: %s', serve_principal(cfg, sshUser, principals))
serve_principal(cfg, sshUser, principals)
log.info('Done.')

View file

@ -36,7 +36,7 @@ def init(
if _git is None:
_git = 'git'
util.mkdir(path, 0750)
util.mkdir(path, 0o750)
args = [
_git,
'--git-dir=.',
@ -131,7 +131,7 @@ class GitCheckoutIndexError(GitExportError):
def export(git_dir, path):
try:
os.mkdir(path)
except OSError, e:
except OSError as e:
if e.errno == errno.EEXIST:
pass
else:
@ -185,7 +185,7 @@ def has_initial_commit(git_dir):
stdout=subprocess.PIPE,
close_fds=True,
)
got = child.stdout.read()
got = child.stdout.read().decode('utf-8')
returncode = child.wait()
if returncode != 0:
raise GitRevParseError('exit status %d' % returncode)

View file

@ -10,7 +10,6 @@ import shutil
from gitosis import repository
from gitosis import ssh
from gitosis import ssh_principals
from gitosis import gitweb
from gitosis import gitdaemon
from gitosis import app
@ -20,7 +19,7 @@ def post_update(cfg, git_dir):
export = os.path.join(git_dir, 'gitosis-export')
try:
shutil.rmtree(export)
except OSError, e:
except OSError as e:
if e.errno == errno.ENOENT:
pass
else:
@ -48,11 +47,6 @@ def post_update(cfg, git_dir):
path=authorized_keys,
keydir=os.path.join(export, 'keydir'),
)
principals = util.getSSHPrincipalsPath(config=cfg)
ssh_principals.writePrincipals(
path=principals,
principals=os.path.join(export, 'keydir/principals'),
)
class Main(app.App):
def create_parser(self):
@ -69,16 +63,18 @@ class Main(app.App):
parser.error('Missing argument HOOK.')
log = logging.getLogger('gitosis.run_hook')
os.umask(0022)
os.umask(0o022)
git_dir = os.environ.get('GIT_DIR')
if git_dir is None:
log.error('Must have GIT_DIR set in enviroment')
sys.exit(1)
else:
log.debug("GIT_DIR %s".format(git_dir))
if hook == 'post-update':
log.info('Running hook %s', hook)
log.info('Running hook %s'.format(hook))
post_update(cfg, git_dir)
log.info('Done.')
else:
log.warning('Ignoring unknown hook: %r', hook)
log.warning('Ignoring unknown hook: %r'.format(hook))

View file

@ -141,7 +141,7 @@ def serve(
p = topdir
for segment in repopath.split(os.sep)[:-1]:
p = os.path.join(p, segment)
util.mkdir(p, 0750)
util.mkdir(p, 0o750)
repository.init(path=fullpath)
gitweb.set_descriptions(
@ -178,7 +178,7 @@ class Main(app.App):
parser.error('Missing argument USER.')
main_log = logging.getLogger('gitosis.serve.main')
os.umask(0022)
os.umask(0o022)
cmd = os.environ.get('SSH_ORIGINAL_COMMAND', None)
if cmd is None:
@ -197,7 +197,7 @@ class Main(app.App):
user=user,
command=cmd,
)
except ServingError, e:
except ServingError as e:
main_log.error('%s', e)
sys.exit(1)

View file

@ -25,7 +25,7 @@ def readKeys(keydir):
continue
path = os.path.join(keydir, filename)
f = file(path)
f = open(path)
for line in f:
line = line.rstrip('\n')
yield (basename, line)
@ -62,24 +62,27 @@ def filterAuthorizedKeys(fp):
def writeAuthorizedKeys(path, keydir):
tmp = '%s.%d.tmp' % (path, os.getpid())
log.debug("writeAuthorizedKeys " + str(tmp) )
try:
in_ = file(path)
except IOError, e:
in_ = open(path)
except IOError as e:
if e.errno == errno.ENOENT:
in_ = None
else:
raise
try:
out = file(tmp, 'w')
out = open(tmp, 'w')
try:
if in_ is not None:
for line in filterAuthorizedKeys(in_):
print >>out, line
#print >>out, line
print(line, file=out)
keygen = readKeys(keydir)
for line in generateAuthorizedKeys(keygen):
print >>out, line
#print >>out, line
print(line, file=out)
os.fsync(out)
finally:

View file

@ -1,82 +0,0 @@
import os, errno, re
import logging
log = logging.getLogger('gitosis.ssh')
_ACCEPTABLE_USER_RE = re.compile(r'^[a-zA-Z][a-zA-Z0-9_.-]*(@[a-zA-Z][a-zA-Z0-9.-]*)?$')
def isSafeUsername(user):
match = _ACCEPTABLE_USER_RE.match(user)
return (match is not None)
def readPrincipals(principals):
"""
Read SSH principals from ``principals``
"""
f = file(principals)
for line in f:
if not isSafeUsername(line):
log.warn('Unsafe SSH username in principalfile: %r', line)
continue
line = line.rstrip('\n')
yield (line)
f.close()
COMMENT = '### autogenerated by gitosis, DO NOT EDIT'
def generatePrincipals(keys):
TEMPLATE=('command="gitosis-serve %(user)s",no-port-forwarding,'
+'no-X11-forwarding,no-agent-forwarding,no-pty %(user)s')
yield COMMENT
for (user) in keys:
log.debug(TEMPLATE % dict(user=user))
yield TEMPLATE % dict(user=user)
_COMMAND_RE = re.compile('^command="(/[^ "]+/)?gitosis-serve [^"]+",no-port-forw'
+'arding,no-X11-forwarding,no-agent-forwardi'
+'ng,no-pty .*')
def filterPrincipals(fp):
"""
Read lines from ``fp``, filter out autogenerated ones.
Note removes newlines.
"""
for line in fp:
line = line.rstrip('\n')
if line == COMMENT:
continue
if _COMMAND_RE.match(line):
continue
yield line
def writePrincipals(path, principals):
tmp = '%s.%d.tmp' % (path, os.getpid())
try:
in_ = file(path)
except IOError, e:
if e.errno == errno.ENOENT:
in_ = None
else:
raise
try:
out = file(tmp, 'w')
try:
if in_ is not None:
for line in filterPrincipals(in_):
print >>out, line
keygen = readPrincipals(principals)
for line in generatePrincipals(keygen):
print >>out, line
os.fsync(out)
finally:
out.close()
finally:
if in_ is not None:
in_.close()
os.rename(tmp, path)

View file

@ -1,7 +1,7 @@
from nose.tools import eq_ as eq
import logging
from ConfigParser import RawConfigParser
from configparser import RawConfigParser
from gitosis import access

View file

@ -1,7 +1,7 @@
from nose.tools import eq_ as eq
import os
from ConfigParser import RawConfigParser
from configparser import RawConfigParser
from gitosis import gitdaemon
from gitosis.test.util import maketemp, writeFile

View file

@ -1,8 +1,8 @@
from nose.tools import eq_ as eq
import os
from ConfigParser import RawConfigParser
from cStringIO import StringIO
from configparser import RawConfigParser
from io import StringIO
from gitosis import gitweb
from gitosis.test.util import mkdir, maketemp, readFile, writeFile

View file

@ -1,6 +1,6 @@
from nose.tools import eq_ as eq, assert_raises
from ConfigParser import RawConfigParser
from configparser import RawConfigParser
from gitosis import group

View file

@ -2,7 +2,7 @@ from nose.tools import eq_ as eq
from gitosis.test.util import assert_raises, maketemp
import os
from ConfigParser import RawConfigParser
from configparser import RawConfigParser
from gitosis import init
from gitosis import repository
@ -113,7 +113,7 @@ def test_init_admin_repository():
'hooks',
'post-update',
)
util.check_mode(hook, 0755, is_file=True)
util.check_mode(hook, 0o755, is_file=True)
got = util.readFile(hook).splitlines()
assert 'gitosis-run-hook post-update' in got
export_dir = os.path.join(tmp, 'export')

View file

@ -23,17 +23,17 @@ def test_init_simple():
tmp = maketemp()
path = os.path.join(tmp, 'repo.git')
repository.init(path)
check_mode(path, 0750, is_dir=True)
check_mode(path, 0o750, is_dir=True)
check_bare(path)
def test_init_exist_dir():
tmp = maketemp()
path = os.path.join(tmp, 'repo.git')
mkdir(path, 0710)
check_mode(path, 0710, is_dir=True)
mkdir(path, 0o710)
check_mode(path, 0o710, is_dir=True)
repository.init(path)
# my weird access mode is preserved
check_mode(path, 0710, is_dir=True)
check_mode(path, 0o710, is_dir=True)
check_bare(path)
def test_init_exist_git():
@ -41,7 +41,7 @@ def test_init_exist_git():
path = os.path.join(tmp, 'repo.git')
repository.init(path)
repository.init(path)
check_mode(path, 0750, is_dir=True)
check_mode(path, 0o750, is_dir=True)
check_bare(path)
def test_init_templates():
@ -53,7 +53,7 @@ def test_init_templates():
)
# for reproducibility
os.umask(0022)
os.umask(0o022)
repository.init(path, template=templatedir)
repository.init(path)
@ -61,7 +61,7 @@ def test_init_templates():
eq(got, 'i should show up\n')
check_mode(
os.path.join(path, 'hooks', 'post-update'),
0755,
0o755,
is_file=True,
)
got = readFile(os.path.join(path, 'hooks', 'post-update'))
@ -91,7 +91,7 @@ PATH="${PATH#*:}"
exec git "$@"
''')
os.chmod(mockgit, 0755)
os.chmod(mockgit, 0o755)
magic_cookie = '%d' % random.randint(1, 100000)
good_path = os.environ['PATH']
try:
@ -130,7 +130,7 @@ PATH="${PATH#*:}"
exec git "$@"
''')
os.chmod(mockgit, 0755)
os.chmod(mockgit, 0o755)
magic_cookie = '%d' % random.randint(1, 100000)
good_path = os.environ['PATH']
try:
@ -226,7 +226,7 @@ PATH="${PATH#*:}"
exec git "$@"
''')
os.chmod(mockgit, 0755)
os.chmod(mockgit, 0o755)
repository.init(path=git_dir)
repository.fast_import(
git_dir=git_dir,
@ -301,7 +301,7 @@ PATH="${PATH#*:}"
exec git "$@"
''')
os.chmod(mockgit, 0755)
os.chmod(mockgit, 0o755)
repository.init(path=tmp)
repository.fast_import(
git_dir=tmp,

View file

@ -1,8 +1,8 @@
from nose.tools import eq_ as eq
import os
from ConfigParser import RawConfigParser
from cStringIO import StringIO
from configparser import RawConfigParser
from io import StringIO
from gitosis import init, repository, run_hook
from gitosis.test.util import maketemp, readFile

View file

@ -3,8 +3,8 @@ from gitosis.test.util import assert_raises
import logging
import os
from cStringIO import StringIO
from ConfigParser import RawConfigParser
from io import StringIO
from configparser import RawConfigParser
from gitosis import serve
from gitosis import repository
@ -354,7 +354,7 @@ def test_push_inits_subdir_parent_missing():
)
eq(os.listdir(repositories), ['foo'])
foo = os.path.join(repositories, 'foo')
util.check_mode(foo, 0750, is_dir=True)
util.check_mode(foo, 0o750, is_dir=True)
eq(os.listdir(foo), ['bar.git'])
assert os.path.isfile(os.path.join(repositories, 'foo', 'bar.git', 'HEAD'))
@ -366,7 +366,7 @@ def test_push_inits_subdir_parent_exists():
os.mkdir(repositories)
foo = os.path.join(repositories, 'foo')
# silly mode on purpose; not to be touched
os.mkdir(foo, 0751)
os.mkdir(foo, 0o751)
cfg.set('gitosis', 'repositories', repositories)
generated = os.path.join(tmp, 'generated')
os.mkdir(generated)
@ -380,7 +380,7 @@ def test_push_inits_subdir_parent_exists():
command="git-receive-pack 'foo/bar.git'",
)
eq(os.listdir(repositories), ['foo'])
util.check_mode(foo, 0751, is_dir=True)
util.check_mode(foo, 0o751, is_dir=True)
eq(os.listdir(foo), ['bar.git'])
assert os.path.isfile(os.path.join(repositories, 'foo', 'bar.git', 'HEAD'))

View file

@ -1,7 +1,7 @@
from nose.tools import eq_ as eq, assert_raises
import os
from cStringIO import StringIO
from io import StringIO
from gitosis import ssh
from gitosis.test.util import mkdir, maketemp, writeFile, readFile
@ -171,7 +171,7 @@ class WriteAuthorizedKeys_Test(object):
def test_simple(self):
tmp = maketemp()
path = os.path.join(tmp, 'authorized_keys')
f = file(path, 'w')
f = open(path, 'w')
try:
f.write('''\
# foo

View file

@ -9,7 +9,7 @@ import sys
def mkdir(*a, **kw):
try:
os.mkdir(*a, **kw)
except OSError, e:
except OSError as e:
if e.errno == errno.EEXIST:
pass
else:
@ -27,7 +27,7 @@ def maketemp():
tmp = os.path.join(tmp, name)
try:
shutil.rmtree(tmp)
except OSError, e:
except OSError as e:
if e.errno == errno.ENOENT:
pass
else:
@ -37,7 +37,7 @@ def maketemp():
def writeFile(path, content):
tmp = '%s.tmp' % path
f = file(tmp, 'w')
f = open(tmp, 'w')
try:
f.write(content)
finally:
@ -45,7 +45,7 @@ def writeFile(path, content):
os.rename(tmp, path)
def readFile(path):
f = file(path)
f = open(path)
try:
data = f.read()
finally:
@ -58,7 +58,7 @@ def assert_raises(excClass, callableObj, *args, **kwargs):
"""
try:
callableObj(*args, **kwargs)
except excClass, e:
except excClass as e:
return e
else:
if hasattr(excClass,'__name__'): excName = excClass.__name__

View file

@ -1,11 +1,11 @@
import errno
import os
from ConfigParser import NoSectionError, NoOptionError
from configparser import NoSectionError, NoOptionError
def mkdir(*a, **kw):
try:
os.mkdir(*a, **kw)
except OSError, e:
except OSError as e:
if e.errno == errno.EEXIST:
pass
else:
@ -41,3 +41,10 @@ def getSSHPrincipalsPath(config):
except (NoSectionError, NoOptionError):
path = os.path.expanduser('~/.ssh/principals')
return path
def getAllowedSSHPrincipals(config):
try:
principals = config.get('gitosis', 'allowedPrincipals')
except (NoSectionError, NoOptionError):
principals = "git"
return principals

View file

@ -45,6 +45,7 @@ arbitrary commands.
'gitosis-serve = gitosis.serve:Main.run',
'gitosis-run-hook = gitosis.run_hook:Main.run',
'gitosis-init = gitosis.init:Main.run',
'gitosis-authorized-principals = gitosis.principals:Main.run',
],
},