source: TI12-security/trunk/python/bin/SimpleCAServer.py @ 1231

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/bin/SimpleCAServer.py@1231
Revision 1231, 8.5 KB checked in by pjkersha, 14 years ago (diff)

setup.py and README: chnage to release 0.70.

NDG/SimpleCA.py: move CA pass-phrase check to AFTER setProperties and readProperties calls so that the
'chkCAPassPhraseExe' key is set.

bin/SimpleCAServer.py: changes command line parser to optparse. Added code to enable server to be run in a
separate process.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/env python
2
3"""NDG Attribute Authority Web Services server interface
4
5NERC Data Grid Project
6
7P J Kershaw 02/08/05
8
9Copyright (C) 2005 CCLRC & NERC
10
11This software may be distributed under the terms of the Q Public License,
12version 1.0 or later.
13"""
14
15reposID = '$Id$'
16
17# Handle socket errors from WS
18import socket 
19
20from ZSI import dispatch
21from NDG.simpleCA_services import reqCertResponseWrapper
22import sys
23from NDG.SimpleCA import *
24
25# Certificate request is a class to encapsulate digital signature handling
26from NDG.CertReq import *
27
28# Command line processing
29import sys
30import os
31import optparse
32
33
34def reqCert(usrCertReq):
35
36    """NDG SimpleCA WS interface for certificate request."""
37   
38    resp = reqCertResponseWrapper()
39    resp._usrCert = ''
40    resp._errMsg = ''
41
42    if options.debug:
43        import pdb
44        pdb.set_trace()     
45
46    # Check digital signature
47    #
48    # Nb. Ensure string is converted from unicode
49    try:
50        certReq = CertReqParse(str(usrCertReq),
51                               certFilePathList=simpleCA['caCertFile'])
52
53        if not certReq.isValidSig():
54            raise Exception("signature for request message is invalid")
55       
56    except Exception, e:
57        resp._errMsg = "Certificate request: %s" % str(e)
58        return resp
59
60   
61    # Request a new X.509 certificate from the CA
62    try:
63        resp._usrCert = simpleCA.sign(certReq.certReqTxt)
64       
65    except Exception, e:
66        resp._errMsg = "New certificate: %s" % e
67   
68    return resp
69
70
71#_____________________________________________________________________________
72def runInForegnd():
73    """Run Simple CA in the same process as this script"""
74   
75    print "Simple CA Server listening..."
76    try:
77         dispatch.AsServer(port=options.port)
78
79    except KeyboardInterrupt:
80        sys.exit(0)
81
82    except socket.error, e:
83        print >>sys.stderr, "Simple CA Server socket error: %s" % e[1]
84        sys.exit(1)
85
86    except Exception, e:
87        print >>sys.stderr, "Simple CA Server: %s" % e
88        sys.exit(1)
89       
90
91#_____________________________________________________________________________
92def fork(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
93    """Run Simple CA in a separate child process
94   
95    Thanks to Jorgen Hermann and user contributors for fork code
96   
97    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012
98   
99    """
100   
101    try: 
102        pid = os.fork() 
103        if pid > 0:
104            # exit first parent
105            sys.exit(0) 
106    except OSError, e: 
107        print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror) 
108        sys.exit(1)
109
110    # Decouple from parent environment
111    os.chdir("/") # Allows for current dir path being renamed or deleted
112    os.setsid() 
113    os.umask(0) 
114   
115    # Redirect standard file descriptors
116    si = file(stdin, 'r')
117    so = file(stdout, 'a+')
118    se = file(stderr, 'a+', 0)
119   
120    sys.stdout.flush()
121    sys.stderr.flush()
122
123    os.dup2(si.fileno(), sys.stdin.fileno())
124    os.dup2(so.fileno(), sys.stdout.fileno())
125    os.dup2(se.fileno(), sys.stderr.fileno())
126   
127
128    # Do second fork
129    try: 
130        pid = os.fork() 
131        if pid > 0:
132            # exit from second parent
133            sys.exit(pid) 
134    except OSError, e: 
135        print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror) 
136        sys.exit(1) 
137
138    # start the daemon main loop
139    try:
140         dispatch.AsServer(port=options.port)
141
142    except socket.error, e:
143        print >>sys.stderr, "Simple CA Server socket error: %s" % e[1]
144        sys.exit(1)
145
146    except Exception, e:
147        print >>sys.stderr, "Simple CA Server: %s" % e
148        sys.exit(1)
149
150
151#_____________________________________________________________________________
152if __name__ == '__main__':
153
154    parser = optparse.OptionParser()
155
156    # Check in installation area otherwise assume local directory
157    propFileDir = 'NDG_DIR' in os.environ and \
158                            os.path.join(os.environ['NDG_DIR'], "conf") or "."
159
160    propFilename = 'simpleCAProperties.xml'
161    parser.add_option("-f",
162                      "--file",
163                      dest="propFilePath",
164                      default=os.path.join(propFileDir, propFilename),
165                      help=\
166"""properties file path - default is $NDG_DIR/%s or ./%s if NDG_DIR is not
167set""" % (propFilename, propFilename))
168
169   
170    parser.add_option("-c",
171                      "--conf",
172                      dest="configFilePath",
173                      default=None,
174                      help=\
175"""path to configuration file used to set CA pass-phrase.  If not set,
176pass-phrase is prompted for from tty.""")
177
178
179    parser.add_option("-s",
180                      "--pass-phrase-from-stdin",
181                      action="store_true",
182                      dest="bPassPhraseFromStdin",
183                      default=False,
184                      help="""\
185Take CA pass-phrase from stdin.  If not set, pass-phrase is prompted for from
186tty.""")
187
188
189    # Port may be set from an environment variable.  Note that this will be
190    # overridden if the port command line argument is set
191    caPortNumEnvVarName = 'NDG_CA_PORT_NUM'
192    defaultPort = 5500
193   
194    initPort = caPortNumEnvVarName in os.environ and \
195                        int(os.environ[caPortNumEnvVarName]) or defaultPort
196           
197    parser.add_option("-p",
198                      "--port",
199                      dest="port",
200                      default=initPort,
201                      type="int",
202                      help=\
203"specify a port number - default is %d or set environment variable \"%s\"" % \
204                                          (defaultPort, caPortNumEnvVarName))
205   
206    foregndFlags = ("-i", "--foreground")
207    parser.add_option(action="store_true",
208                      dest="foregndProc",
209                      default=False,
210                      help=\
211"run server as process in the foreground.  If not set, fork a child process",
212                      *foregndFlags)
213   
214    parser.add_option("-d",
215                      "--debug",
216                      action="store_true",
217                      dest="debug",
218                      default=False,
219                      help=\
220"set to stop in debugger on receipt of WS request.  %s flag must be set also"\
221                                            % '/'.join(foregndFlags))
222                                           
223    (options, args) = parser.parse_args()
224
225       
226    # Create server instance at start up - pass in config file path in case
227    # this was set on the command line
228    try:
229        simpleCA = SimpleCA(propFilePath=options.propFilePath,
230                            configFilePath=options.configFilePath)
231    except Exception, e:
232        print >>sys.stderr, "Initialising Simple CA: %s" % e
233        sys.exit(1)
234
235
236    # Check in case pass-phrase was not set via config file option
237    try:
238        if options.bPassPhraseFromStdin:
239           
240            # Pass-phrase may be set from stdin
241            try:
242                simpleCA.caPassPhrase = sys.stdin.read().strip()
243               
244            except SimpleCAPassPhraseError, e:
245                print >>sys.stderr, "Invalid pass-phrase set from stdin"
246                sys.exit(1)
247                   
248        elif options.configFilePath is None:
249           
250            # No configuration file was set either - read from user input at
251            # terminal
252            import getpass
253   
254            nTries = 0
255            while nTries < 10:
256                try:
257                    simpleCA.caPassPhrase = \
258                        getpass.getpass(prompt="Simple CA Pass-phrase: ")
259                    break
260               
261                except KeyboardInterrupt:
262                    sys.exit(1)
263                   
264                except SimpleCAPassPhraseError, e:
265                    nTries += 1
266                    if nTries >= 10:
267                        print >>sys.stderr, \
268                            "Invalid Pass-phrase - exiting after 10 attempts"
269                        sys.exit(1)
270                    else:
271                        print >>sys.stderr, "Invalid pass-phrase"
272           
273    except Exception, e:
274        # Catch all
275        print >>sys.stderr, "Error checking Simple CA pass-phrase: %s" % e
276        sys.exit(1)
277       
278
279    if options.foregndProc:
280        runInForegnd()
281    else:
282        if options.debug:
283            print >>sys.stderr, "%s must be set with debug option" % \
284                                                    '/'.join(foregndFlags)
285            parser.print_help()
286            sys.exit(1)
287           
288        # Run server in child process
289        fork() 
Note: See TracBrowser for help on using the repository browser.