PageRenderTime 56ms CodeModel.GetById 10ms app.highlight 25ms RepoModel.GetById 5ms app.codeStats 0ms

/neatx/test/python/neatx.auth_test.py

http://neatx.googlecode.com/
Python | 221 lines | 150 code | 50 blank | 21 comment | 10 complexity | 78c5fb03aa624bd100994103a8fc4916 MD5 | raw file
  1#!/usr/bin/python
  2#
  3
  4# Copyright (C) 2009 Google Inc.
  5#
  6# This program is free software; you can redistribute it and/or modify
  7# it under the terms of the GNU General Public License as published by
  8# the Free Software Foundation; either version 2 of the License, or
  9# (at your option) any later version.
 10#
 11# This program is distributed in the hope that it will be useful, but
 12# WITHOUT ANY WARRANTY; without even the implied warranty of
 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14# General Public License for more details.
 15#
 16# You should have received a copy of the GNU General Public License
 17# along with this program; if not, write to the Free Software
 18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 19# 02110-1301, USA.
 20
 21
 22"""Script for unittesting the auth module"""
 23
 24
 25import os
 26import re
 27import tempfile
 28import unittest
 29
 30from neatx import auth
 31from neatx import constants
 32from neatx import errors
 33from neatx import utils
 34
 35
 36DUMMY_USER = "dummyuser"
 37DUMMY_USER2 = "anotheruser"
 38DUMMY_PASSWORD = "Pa$$W0rd"
 39DUMMY_PASSWORD2 = "something"
 40
 41
 42def _WriteAuthScript(confirmation):
 43  (fd, name) = tempfile.mkstemp()
 44  try:
 45    os.chmod(name, 0700)
 46
 47    try:
 48      def w(*args):
 49        for i in args:
 50          os.write(fd, i)
 51        os.write(fd, "\n")
 52
 53      w("#!", constants.BASH)
 54      w("DUMMY_USER='", DUMMY_USER, "'")
 55      w("DUMMY_PASSWORD='", DUMMY_PASSWORD, "'")
 56      w("user=$1; shift")
 57      w("if [[ \"$user\" != \"$DUMMY_USER\" ]]; then")
 58      w("  echo 'Unknown user'")
 59      w("  exit 1")
 60      w("fi")
 61      w("read -s -p 'Password: ' pw < /dev/tty")
 62      w("echo")
 63      w("if [[ \"$pw\" != \"$DUMMY_PASSWORD\" ]]; then")
 64      w("  echo 'Authentication failed'")
 65      w("  exit 1")
 66      w("fi")
 67      if confirmation:
 68        w("echo Authentication successful")
 69      w("exec \"$@\"")
 70    finally:
 71      os.close(fd)
 72  except:
 73    utils.RemoveFile(name)
 74    raise
 75
 76  return name
 77
 78
 79class _DummyPasswordAuth:
 80  def __init__(self, cfg):
 81    pass
 82
 83
 84class _DummyLdapAuth:
 85  def __init__(self, cfg):
 86    pass
 87
 88
 89class _DummyAuth(auth._ExpectAuthBase):
 90  def __init__(self, cfg, authcmd, stdout_fileno, stdin_fileno):
 91    auth._ExpectAuthBase.__init__(self, cfg,
 92                                  stdout_fileno=stdout_fileno,
 93                                  stdin_fileno=stdin_fileno)
 94    self._authcmd = authcmd
 95
 96  def GetCommand(self, username, args):
 97    return [self._authcmd, username] + args
 98
 99  def GetPasswordPrompt(self):
100    return re.compile(r"^Password:\s*", re.I)
101
102  def _GetFdCopyPath(self):
103    return "src/fdcopy"
104
105  def _GetTtySetupPath(self):
106    return "src/ttysetup"
107
108
109class _FakeAuthConfig:
110  def __init__(self, auth_method):
111    self.auth_method = auth_method
112
113    self.auth_ssh_host = "localhost"
114    self.auth_ssh_port = 22
115
116    self.su = constants.SU
117    self.ssh = constants.SSH
118
119
120class TestGetAuthenticator(unittest.TestCase):
121  """Tests for GetAuthenticator"""
122
123  def test(self):
124    dummy_map = {
125      "password": _DummyPasswordAuth,
126      "ldap": _DummyLdapAuth,
127      }
128
129    authenticator = auth.GetAuthenticator(_FakeAuthConfig("password"),
130                                          _method_map=dummy_map)
131    self.failUnless(isinstance(authenticator, _DummyPasswordAuth))
132    self.failIf(isinstance(authenticator, _DummyLdapAuth))
133
134    authenticator = auth.GetAuthenticator(_FakeAuthConfig("ldap"),
135                                          _method_map=dummy_map)
136    self.failUnless(isinstance(authenticator, _DummyLdapAuth))
137    self.failIf(isinstance(authenticator, _DummyPasswordAuth))
138
139    self.failUnlessRaises(errors.UnknownAuthMethod, auth.GetAuthenticator,
140                          _FakeAuthConfig("nonexisting"),
141                          _method_map=dummy_map)
142
143
144class TestExpectAuthBase(unittest.TestCase):
145  """Tests for _ExpectAuthBase"""
146
147  def testGetCommand(self):
148    cfg = _FakeAuthConfig("dummy")
149    username = "NXtestNX"
150    command = "/NX/test/NX"
151
152    for (cls, wanted_arg0) in [(auth.SuAuth, constants.SU),
153                               (auth.SshAuth, constants.SSH)]:
154      args = cls(cfg).GetCommand(username, [command, "a", "b"])
155      self.failUnlessEqual(args[0], wanted_arg0)
156      self.failUnless(username in args)
157      self.failUnless(filter(lambda value: ("%s a b" % command) in value,
158                             args))
159
160  def testAuth(self):
161    authcmd = _WriteAuthScript(False)
162    try:
163      nullfile = tempfile.TemporaryFile()
164      input = tempfile.TemporaryFile()
165      cfg = _FakeAuthConfig("dummy")
166
167      authenticator = _DummyAuth(cfg, authcmd, nullfile.fileno(),
168                                 input.fileno())
169
170      authenticator.AuthenticateAndRun(DUMMY_USER, DUMMY_PASSWORD,
171                                       ["/bin/echo", "NX> "])
172      authenticator.AuthenticateAndRun(DUMMY_USER, DUMMY_PASSWORD,
173                                       ["/bin/echo", "NX> 105"])
174
175      self.failUnlessRaises(errors.AuthFailedError,
176                            authenticator.AuthenticateAndRun,
177                            DUMMY_USER, DUMMY_PASSWORD2,
178                            ["/bin/echo", "NX> 105"])
179
180      self.failUnlessRaises(errors.AuthFailedError,
181                            authenticator.AuthenticateAndRun,
182                            DUMMY_USER2, DUMMY_PASSWORD,
183                            ["/bin/echo", "NX> 105"])
184
185      self.failUnlessRaises(errors.AuthFailedError,
186                            authenticator.AuthenticateAndRun,
187                            DUMMY_USER, DUMMY_PASSWORD,
188                            ["/bin/echo", "ERROR"])
189    finally:
190      utils.RemoveFile(authcmd)
191
192  def testAuthOutput(self):
193    expected = "NX> 105\n" + (1000 * "Hello World\n")
194    cmd = ("set -e;"
195           "echo 'NX> 105';"
196           "for ((i=0; i<1000; ++i)); do"
197           "  echo 'Hello World';"
198           "done")
199
200    for confirmation in [False, True]:
201      dummyout = tempfile.TemporaryFile()
202      input = tempfile.TemporaryFile()
203      cfg = _FakeAuthConfig("dummy")
204
205      authcmd = _WriteAuthScript(confirmation)
206      try:
207        authenticator = _DummyAuth(cfg, authcmd, dummyout.fileno(),
208                                   input.fileno())
209
210        authenticator.AuthenticateAndRun(DUMMY_USER, DUMMY_PASSWORD,
211                                         [constants.BASH, "-c", cmd])
212      finally:
213        utils.RemoveFile(authcmd)
214
215      os.lseek(dummyout.fileno(), 0, 0)
216      data = os.read(dummyout.fileno(), len(expected) * 2)
217      self.failUnlessEqual(data, expected)
218
219
220if __name__ == '__main__':
221  unittest.main()