예제 #1
0
def add_tracker_admin(configuration, cert_id, vgrid_name, tracker_dir,
                      output_objects):
    """Add new Trac issue tracker owner"""
    cgi_tracker_var = os.path.join(tracker_dir, 'var')
    if not os.path.isdir(cgi_tracker_var):
        output_objects.append(
            {'object_type': 'text', 'text'
             : 'No tracker (%s) for %s %s - skipping tracker admin rights' \
             % (tracker_dir, configuration.site_vgrid_label, vgrid_name)
             })
        return (output_objects, returnvalues.SYSTEM_ERROR)
    try:
        admin_user = distinguished_name_to_user(cert_id)
        admin_id = admin_user.get(configuration.trac_id_field, 'unknown_id')
        # Give admin rights to owner using trac-admin command:
        # trac-admin tracker_dir deploy cgi_tracker_bin
        perms_cmd = [configuration.trac_admin_path, cgi_tracker_var,
                     'permission', 'add', admin_id, 'TRAC_ADMIN']
        configuration.logger.info('provide admin rights to owner: %s' % \
                                  perms_cmd)
        proc = subprocess.Popen(perms_cmd, stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
        proc.wait()
        if proc.returncode != 0:
            raise Exception("tracker permissions %s failed: %s (%d)" % \
                            (perms_cmd, proc.stdout.read(),
                             proc.returncode))
        return True
    except Exception, exc:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Could not give %s tracker admin rights: %s' % (cert_id, exc)
             })
        return False
예제 #2
0
def parse_contents(user_data):
    """Extract users from data dump - We simply catch all occurences
    of anything looking like a DN (/ABC=bla bla/DEF=more words/...)
    """

    users = []
    for user_creds in re.findall('/[a-zA-Z]+=[^<]+', user_data):
        user_dict = distinguished_name_to_user(user_creds)
        users.append(user_dict)
    return users
예제 #3
0
파일: fakecgi.py 프로젝트: heromod/migrid
if len(sys.argv) < 2:
    usage()
    sys.exit(1)

script = sys.argv[1]
query = ''
method = 'GET'
run_as_dn = '/C=DK/ST=NA/L=NA/O=NBI/OU=NA/CN=Test User/[email protected]'
if sys.argv[2:]:
    method = sys.argv[2]
if sys.argv[:3]:
    query = sys.argv[3]
if sys.argv[:4]:
    run_as_dn = sys.argv[4]

run_as_user = distinguished_name_to_user(run_as_dn)

extra_environment = {
    'REQUEST_METHOD': method,
    'SERVER_PROTOCOL': 'HTTP/1.1',
    'GATEWAY_INTERFACE': 'CGI/1.1',
    'PATH': '/bin:/usr/bin:/usr/local/bin',
    'REMOTE_ADDR': '127.0.0.1',
    'SSL_CLIENT_S_DN': run_as_user['distinguished_name'],
    'SSL_CLIENT_S_DN_C': run_as_user['country'],
    'SSL_CLIENT_S_DN_O': run_as_user['organization'],
    'SSL_CLIENT_S_DN_OU': run_as_user['organizational_unit'],
    'SSL_CLIENT_S_DN_L': run_as_user['locality'],
    'SSL_CLIENT_S_DN_CN': run_as_user['full_name'],
    'SSL_CLIENT_I_DN': '/C=DK/ST=Denmark/O=IMADA/OU=MiG/CN=MiGCA',
    'SSL_CLIENT_I_DN_C': 'DK',
예제 #4
0
파일: reqcert.py 프로젝트: heromod/migrid
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False, op_menu=False)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input(user_arguments_dict,
            defaults, output_objects, allow_rejects=False)
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s certificate request' % configuration.short_title
    title_entry['skipmenu'] = True
    form_fields = ['full_name', 'organization', 'email', 'country', 'state',
                   'password', 'verifypassword', 'comment']
    title_entry['style'] = themed_styles(configuration)
    title_entry['javascript'] = cert_js_helpers(form_fields)
    output_objects.append({'object_type': 'html_form',
                           'text':'''
 <div id="contextual_help">
  <div class="help_gfx_bubble"><!-- graphically connect field with help text --></div>
  <div class="help_message"><!-- filled by js --></div>
 </div>
'''                       })
    header_entry = {'object_type': 'header', 'text'
                    : 'Welcome to the %s certificate request page' % \
                    configuration.short_title}
    output_objects.append(header_entry)
    
    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.user_home,
                               client_dir)) + os.sep

    user_fields = {'full_name': '', 'organization': '', 'email': '',
                   'state': '', 'country': '', 'password': '',
                   'verifypassword': ''}
    if not os.path.isdir(base_dir) and client_id:

        # Redirect to extcert page with certificate requirement but without
        # changing access method (CGI vs. WSGI).

        extcert_url = os.environ['REQUEST_URI'].replace('-sid', '-bin')
        extcert_url = os.path.join(os.path.dirname(extcert_url), 'extcert.py')
        extcert_link = {'object_type': 'link', 'destination': extcert_url,
                        'text': 'Sign up with existing certificate (%s)' % client_id}
        output_objects.append({'object_type': 'warning', 'text'
                              : 'Apparently you already have a suitable %s certificate that you may sign up with:' % \
                                configuration.short_title
                              })
        output_objects.append(extcert_link)
        output_objects.append({'object_type': 'warning', 'text'
                              : 'However, if you want a dedicated %s certificate you can still request one below:' % \
                                configuration.short_title
                              })
    elif client_id:
        for entry in (title_entry, header_entry):
            entry['text'] = entry['text'].replace('request', 'request / renew')
        output_objects.append({'object_type': 'html_form', 'text'
                              : '''<p>
Apparently you already have a valid %s certificate, but if it is about to
expire you can renew it by posting the form below. Renewal with changed fields
is <span class=mandatory>not</span> supported, so all fields including your
original password must remain unchanged for renew to work. Otherwise it
results in a request for a new account and certificate without access to your
old files, jobs and privileges.</p>''' % \
                               configuration.short_title})
        user_fields.update(distinguished_name_to_user(client_id))

    user_fields.update({
        'valid_name_chars': html_escape(valid_name_chars),
        'valid_password_chars': html_escape(valid_password_chars),
        'password_min_len': password_min_len,
        'password_max_len': password_max_len,
        'site': configuration.short_title
        })

    output_objects.append({'object_type': 'html_form', 'text'
                          : """
Please enter your information in at least the <span class=mandatory>mandatory</span> fields below and press the Send button to submit the certificate request to the %(site)s administrators.
<p class='criticaltext highlight_message'>
IMPORTANT: Please help us verify your identity by providing Organization and Email data that we can easily validate!<br />
That is, if You're a student/employee at KU, please enter institute acronym (NBI, DIKU, etc.) in the Organization field and use your corresponding [email protected] or USER@*.ku.dk address in the Email field.
</p>
<hr />
<div class=form_container>
<!-- use post here to avoid field contents in URL -->
<form method=post action=reqcertaction.py onSubmit='return validate_form();'>
<table>
<tr><td class='mandatory label'>Full name</td><td><input id='full_name_field' type=text name=cert_name value='%(full_name)s' /></td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Email address</td><td><input id='email_field' type=text name=email value='%(email)s' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Organization</td><td><input id='organization_field' type=text name=org value='%(organization)s' /></td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Two letter country-code</td><td><input id='country_field' type=text name=country maxlength=2 value='%(country)s' /></td><td class=fill_space><br /></td></tr>
<tr><td class='optional label'>State</td><td><input id='state_field' type=text name=state value='%(state)s' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Password</td><td><input id='password_field' type=password name=password maxlength=%(password_max_len)s value='%(password)s' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Verify password</td><td><input id='verifypassword_field' type=password name=verifypassword maxlength=%(password_max_len)s value='%(verifypassword)s' /></td><td class=fill_space><br /></td></tr>
<tr><td class='optional label'>Optional comment or reason why you should<br />be granted a %(site)s certificate:</td><td><textarea id='comment_field' rows=4 name=comment></textarea></td><td class=fill_space><br /></td></tr>
<tr><td class='label'><!-- empty area --></td><td><input id='submit_button' type=submit value=Send /></td><td class=fill_space><br /></td></tr>
</table>
</form>
</div>
<hr />
<br />
<div class='warn_message'>Please note that passwords may be accessible to the %(site)s administrators!</div>
<br />
<!-- Hidden help text -->
<div id='help_text'>
  <div id='full_name_help'>Your full name, restricted to the characters in '%(valid_name_chars)s'</div>
  <div id='organization_help'>Organization name or acronym  matching email</div>
  <div id='email_help'>Email address associated with your organization if at all possible</div>
  <div id='country_help'>Country code of your organization and on the form DE/DK/GB/US/.. , <a href='http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.html'>help</a></div>
  <div id='state_help'>Optional state of your organization, please just leave empty unless it is in the US or similar</div>
  <div id='password_help'>Password is restricted to the characters in '%(valid_password_chars)s and must be %(password_min_len)s to %(password_max_len)s characters long'</div>
  <div id='verifypassword_help'>Please repeat password</div>
  <div id='comment_help'>Optional, but a short informative comment may help us verify your certificate needs and thus speed up our response.</div>
</div>
""" % user_fields})

    return (output_objects, returnvalues.OK)
예제 #5
0
def main(client_id, user_arguments_dict, environ=None):
    """Main function used by front end"""

    if environ is None:
        environ = os.environ
    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False, op_menu=False)
    logger = configuration.logger
    logger.info('%s: args: %s' % (op_name, user_arguments_dict))
    prefilter_map = {}
    
    output_objects.append({'object_type': 'header', 'text'
                          : 'Automatic %s sign up' % \
                            configuration.short_title })
    identity = extract_client_openid(configuration, environ, lookup_dn=False)
    if client_id and client_id == identity:
        login_type = 'cert'
        base_url = configuration.migserver_https_cert_url
    elif identity:
        login_type = 'oid'
        base_url = configuration.migserver_https_oid_url
        for name in ('openid.sreg.cn', 'openid.sreg.fullname',
                     'openid.sreg.full_name'):
            prefilter_map[name] = filter_commonname
    else:
        output_objects.append(
            {'object_type': 'error_text', 'text': 'Missing user credentials'})
        return (output_objects, returnvalues.CLIENT_ERROR)
    defaults = signature(login_type)[1]
    (validate_status, accepted) = validate_input(
        user_arguments_dict, defaults, output_objects, allow_rejects=False,
        prefilter_map=prefilter_map)
    if not validate_status:
        logger.warning('%s invalid input: %s' % (op_name, accepted))
        return (accepted, returnvalues.CLIENT_ERROR)

    logger.debug('Accepted arguments: %s' % accepted)

    # Unfortunately OpenID redirect does not use POST
    if login_type != 'oid' and not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    admin_email = configuration.admin_email
    openid_names, oid_extras = [], {}

    # Extract raw values
    if login_type == 'cert':
        uniq_id = accepted['cert_id'][-1].strip()
        raw_name = accepted['cert_name'][-1].strip()
        country = accepted['country'][-1].strip()
        state = accepted['state'][-1].strip()
        org = accepted['org'][-1].strip()
        org_unit = ''
        role = ','.join([i for i in accepted['role'] if i])
        locality = ''
        timezone = ''
        email = accepted['email'][-1].strip()
        raw_login = None
    elif login_type == 'oid':
        uniq_id = accepted['openid.sreg.nickname'][-1].strip() or \
                   accepted['openid.sreg.short_id'][-1].strip()
        raw_name = accepted['openid.sreg.fullname'][-1].strip() or \
                    accepted['openid.sreg.full_name'][-1].strip()
        country = accepted['openid.sreg.country'][-1].strip()
        state = accepted['openid.sreg.state'][-1].strip()
        org = accepted['openid.sreg.o'][-1].strip() or \
              accepted['openid.sreg.organization'][-1].strip()
        org_unit = accepted['openid.sreg.ou'][-1].strip() or \
                   accepted['openid.sreg.organizational_unit'][-1].strip()
        # We may receive multiple roles
        role = ','.join([i for i in accepted['openid.sreg.role'] if i])
        locality = accepted['openid.sreg.locality'][-1].strip()
        timezone = accepted['openid.sreg.timezone'][-1].strip()
        email = accepted['openid.sreg.email'][-1].strip()

    # Fix case of values:
    # force name to capitalized form (henrik karlsen -> Henrik Karlsen)
    # please note that we get utf8 coded bytes here and title() treats such
    # chars as word termination. Temporarily force to unicode.
    try:
        full_name = force_utf8(force_unicode(raw_name).title())
    except Exception:
        logger.warning("could not use unicode form to capitalize full name")
        full_name = raw_name.title()
    country = country.upper()
    state = state.upper()
    email = email.lower()

    if login_type == 'oid':
        # Remap some oid attributes if on kit format with faculty in
        # organization and institute in organizational_unit. We can add them
        # as different fields as long as we make sure the x509 fields are
        # preserved.
        # We do that to allow autocreate updating existing cert users.
        
        if org_unit not in ('', 'NA'):
            org_unit = org_unit.upper()
            oid_extras['faculty'] = org
            oid_extras['institute'] = org_unit
            org = org_unit.upper()
            org_unit = 'NA'

        # Stay on virtual host - extra useful while we test dual OpenID
        base_url = environ.get('REQUEST_URI',
                               base_url).split('?')[0].replace('autocreate',
                                                               'fileman')
        raw_login = None
        for oid_provider in configuration.user_openid_providers:
            openid_prefix = oid_provider.rstrip('/') + '/'
            if identity.startswith(openid_prefix):
                raw_login = identity.replace(openid_prefix, '')
                break

    if raw_login:
        openid_names.append(raw_login)

    # we should have the proxy file read...
    proxy_content = accepted['proxy_upload'][-1]

    # keep comment to a single line

    comment = accepted['comment'][-1].replace('\n', '   ')

    # single quotes break command line format - remove

    comment = comment.replace("'", ' ')

    user_dict = {
        'short_id': uniq_id,
        'full_name': full_name,
        'organization': org,
        'organizational_unit': org_unit,
        'locality': locality,
        'state': state,
        'country': country,
        'email': email,
        'role': role,
        'timezone': timezone,
        'password': '',
        'comment': '%s: %s' % ('Existing certificate', comment),
        'openid_names': openid_names,
        }
    user_dict.update(oid_extras)

    # We must receive some ID from the provider
    if not uniq_id and not email:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'No ID information received!'})
        if accepted.get('openid.sreg.required', '') and \
               identity:
            # Stay on virtual host - extra useful while we test dual OpenID
            url = environ.get('REQUEST_URI',
                              base_url).split('?')[0].replace('autocreate',
                                                              'logout')
            output_objects.append(
                {'object_type': 'text', 'text': '''Please note that sign-up
for OpenID access does not work if you are already signed in with your OpenID
provider - and that appears to be the case now.
You probably have to reload this page after you explicitly '''})
            output_objects.append(        
                {'object_type': 'link', 'destination': url,
                 'target': '_blank', 'text': "Logout"
                 })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if login_type == 'cert':
        user_dict['expire'] = int(time.time() + cert_valid_days * 24 * 60 * 60)
        try:
            distinguished_name_to_user(uniq_id)
            user_dict['distinguished_name'] = uniq_id
        except:
            output_objects.append({'object_type': 'error_text', 'text'
                                   : '''Illegal Distinguished name:
Please note that the distinguished name must be a valid certificate DN with
multiple "key=val" fields separated by "/".
'''})
            return (output_objects, returnvalues.CLIENT_ERROR)
    elif login_type == 'oid':
        user_dict['expire'] = int(time.time() + oid_valid_days * 24 * 60 * 60)
        fill_distinguished_name(user_dict)
        uniq_id = user_dict['distinguished_name']

    # If server allows automatic addition of users with a CA validated cert
    # we create the user immediately and skip mail
    
    if login_type == 'cert' and configuration.auto_add_cert_user or \
           login_type == 'oid' and configuration.auto_add_oid_user:
        fill_user(user_dict)

        logger.info('create user: %s' % user_dict)
        
        # Now all user fields are set and we can begin adding the user

        db_path = os.path.join(configuration.mig_server_home, user_db_filename)
        try:
            create_user(user_dict, configuration.config_file, 
                        db_path, ask_renew=False, default_renew=True)
            if configuration.site_enable_griddk and \
                   accepted['proxy_upload'] != ['']:
                # save the file, display expiration date
                proxy_out = handle_proxy(proxy_content, uniq_id, 
                                         configuration)
                output_objects.extend(proxy_out)
        except Exception, err:
            logger.error('create failed for %s: %s' % (uniq_id, err))
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : '''Could not create the user account for you:
Please report this problem to the grid administrators (%s).''' % \
                 admin_email})
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({'object_type': 'html_form', 'text'
                                   : '''Created the user account for you -
please open <a href="%s">your personal page</a> to proceed using it.
''' % base_url})
        return (output_objects, returnvalues.OK)
예제 #6
0
def create_tracker(
    configuration,
    client_id,
    vgrid_name,
    tracker_dir,
    scm_dir,
    output_objects,
    repair=False
    ):
    """Create new Trac issue tracker bound to SCM repository if given"""

    logger = configuration.logger
    kind = 'member'
    tracker_alias = 'vgridtracker'
    admin_user = distinguished_name_to_user(client_id)
    admin_email = admin_user.get('email', '*****@*****.**')
    admin_id = admin_user.get(configuration.trac_id_field, 'unknown_id')
    server_url = configuration.migserver_https_default_url
    if tracker_dir.find('private') > -1:
        kind = 'owner'
        tracker_alias = 'vgridownertracker'
        server_url = configuration.migserver_https_default_url
    elif tracker_dir.find('public') > -1:
        kind = 'public'
        tracker_alias = 'vgridpublictracker'
        server_url = configuration.migserver_http_url
    tracker_url = os.path.join(server_url, tracker_alias, vgrid_name)

    # Trac init is documented at http://trac.edgewall.org/wiki/TracAdmin
    target_tracker_var = os.path.join(tracker_dir, 'var')
    target_tracker_conf = os.path.join(target_tracker_var, 'conf')
    target_tracker_conf_file = os.path.join(target_tracker_conf, 'trac.ini')
    tracker_db = 'sqlite:db/trac.db'
    # NB: deploy command requires an empty directory target
    # We create a lib dir where it creates cgi-bin and htdocs subdirs
    # and we then symlink both a parent cgi-bin and wsgi-bin to it
    target_tracker_deploy = os.path.join(tracker_dir, 'lib')
    target_tracker_bin = os.path.join(target_tracker_deploy, 'cgi-bin')
    target_tracker_cgi_link = os.path.join(tracker_dir, 'cgi-bin')
    target_tracker_wsgi_link = os.path.join(tracker_dir, 'wsgi-bin')
    target_tracker_gvcache = os.path.join(target_tracker_var, 'gvcache')
    target_tracker_downloads = os.path.join(target_tracker_var, 'downloads')
    target_tracker_log = os.path.join(target_tracker_var, 'log')
    target_tracker_log_file = os.path.join(target_tracker_log, 'trac.log')
    repo_base = 'repo'
    target_scm_repo = os.path.join(scm_dir, repo_base)
    project_name = '%s %s project tracker' % (vgrid_name, kind)
    create_cmd = None
    create_status = True
    # Trac requires this for certain versions of setuptools
    # http://trac.edgewall.org/wiki/setuptools
    admin_env = os.environ.copy()
    admin_env["PKG_RESOURCES_CACHE_ZIP_MANIFESTS"] = "1"    
    try:

        # Create tracker directory

        if not repair or not os.path.isdir(tracker_dir):
            logger.info('create tracker dir: %s' % tracker_dir)
            os.mkdir(tracker_dir)
        else:
            logger.info('write enable tracker dir: %s' % tracker_dir)
            os.chmod(tracker_dir, 0755)
            
        # Create Trac project that uses local storage.
        # In this way modification to one vgrid tracker will not affect others.

        if not repair or not os.path.isdir(target_tracker_var):
            # Init tracker with trac-admin command:
            # trac-admin tracker_dir initenv projectname db respostype repospath
            create_cmd = [configuration.trac_admin_path, target_tracker_var,
                          'initenv', vgrid_name, tracker_db, 'hg',
                          target_scm_repo]
            # Trac may fail silently if ini file is missing
            if configuration.trac_ini_path and \
                   os.path.exists(configuration.trac_ini_path):
                create_cmd.append('--inherit=%s' % configuration.trac_ini_path)

            # IMPORTANT: trac commands are quite verbose and will cause trouble
            # if the stdout/err is not handled (Popen vs call)
            logger.info('create tracker project: %s' % create_cmd)
            proc = subprocess.Popen(create_cmd, stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT, env=admin_env)
            proc.wait()
            if proc.returncode != 0:
                raise Exception("tracker creation %s failed: %s (%d)" % \
                                (create_cmd, proc.stdout.read(),
                                 proc.returncode))

            # We want to customize generated project trac.ini with project info
        
            conf = ConfigParser.SafeConfigParser()
            conf.read(target_tracker_conf_file)

            conf_overrides = {
                'trac': {
                    'base_url': tracker_url,
                    },
                'project': {
                    'admin': admin_email,
                    'descr': project_name,
                    'footer': "",
                    'url': tracker_url,
                    },
                'header_logo': {
                    'height': -1,
                    'width': -1,
                    'src': os.path.join(server_url, 'images', 'site-logo.png'),
                    'link': '',
                    },
                }
            if configuration.smtp_server:
                (from_name, from_addr) = parseaddr(configuration.smtp_sender)
                from_name += ": %s %s project tracker" % (vgrid_name, kind)
                conf_overrides['notification'] = {
                    'smtp_from': from_addr,
                    'smtp_from_name': from_name,
                    'smtp_server': configuration.smtp_server,
                    'smtp_enabled': True,
                    }

            for (section, options) in conf_overrides.items():
                if not conf.has_section(section):
                    conf.add_section(section)
                for (key, val) in options.items():
                    conf.set(section, key, str(val))

            project_conf = open(target_tracker_conf_file, "w")
            project_conf.write("# -*- coding: utf-8 -*-\n")
            # dump entire conf file
            for section in conf.sections():
                project_conf.write("\n[%s]\n" % section)
                for option in conf.options(section):
                    project_conf.write("%s = %s\n" %
                                       (option, conf.get(section, option)))
            project_conf.close()

        if not repair or not os.path.isdir(target_tracker_deploy):
            # Some plugins require DB changes so we always force DB update here
            # Upgrade environment using trac-admin command:
            # trac-admin tracker_dir upgrade
            upgrade_cmd = [configuration.trac_admin_path, target_tracker_var,
                           'upgrade']
            logger.info('upgrade project tracker database: %s' % upgrade_cmd)
            proc = subprocess.Popen(upgrade_cmd, stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT, env=admin_env)
            proc.wait()
            if proc.returncode != 0:
                raise Exception("tracker 1st upgrade db %s failed: %s (%d)" % \
                                (upgrade_cmd, proc.stdout.read(),
                                 proc.returncode))

            # Create cgi-bin with scripts using trac-admin command:
            # trac-admin tracker_dir deploy target_tracker_bin
            deploy_cmd = [configuration.trac_admin_path, target_tracker_var,
                          'deploy', target_tracker_deploy]
            logger.info('deploy tracker project: %s' % deploy_cmd)
            proc = subprocess.Popen(deploy_cmd, stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT, env=admin_env)
            proc.wait()
            if proc.returncode != 0:
                raise Exception("tracker deployment %s failed: %s (%d)" % \
                                (deploy_cmd, proc.stdout.read(),
                                 proc.returncode))

        if not repair or not os.path.isdir(target_tracker_cgi_link):
            os.chmod(target_tracker_var, 0755)
            os.symlink(target_tracker_bin, target_tracker_cgi_link)
        if not repair or not os.path.isdir(target_tracker_wsgi_link):
            os.chmod(target_tracker_var, 0755)
            os.symlink(target_tracker_bin, target_tracker_wsgi_link)
        if not repair or not os.path.isdir(target_tracker_gvcache):
            os.chmod(target_tracker_var, 0755)
            os.mkdir(target_tracker_gvcache)
        if not repair or not os.path.isdir(target_tracker_downloads):
            os.chmod(target_tracker_var, 0755)
            os.mkdir(target_tracker_downloads)
        if not repair or not os.path.isfile(target_tracker_log_file):
            os.chmod(target_tracker_log, 0755)
            open(target_tracker_log_file, 'w').close()

        if not repair or create_cmd:
            # Give admin rights to creator using trac-admin command:
            # trac-admin tracker_dir permission add ADMIN_ID PERMISSION
            perms_cmd = [configuration.trac_admin_path, target_tracker_var,
                         'permission', 'add', admin_id, 'TRAC_ADMIN']
            logger.info('provide admin rights to creator: %s' % perms_cmd)
            proc = subprocess.Popen(perms_cmd, stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT)
            proc.wait()
            if proc.returncode != 0:
                raise Exception("tracker permissions %s failed: %s (%d)" % \
                                (perms_cmd, proc.stdout.read(),
                                 proc.returncode))

            # Customize Wiki front page using trac-admin commands:
            # trac-admin tracker_dir wiki export WikiStart tracinfo.txt
            # trac-admin tracker_dir wiki import AboutTrac tracinfo.txt
            # trac-admin tracker_dir wiki import WikiStart welcome.txt
            # trac-admin tracker_dir wiki import SiteStyle style.txt

            settings = {'vgrid_name': vgrid_name, 'kind': kind, 'cap_kind':
                        kind.capitalize(), 'server_url':  server_url,
                        'css_wikipage': 'SiteStyle',
                        '_label': configuration.site_vgrid_label}
            if kind == 'public':
                settings['access_limit'] = "public"
                settings['login_info'] = """
This %(access_limit)s page requires you to register to get a login. The owners
of the %(_label)s will then need to give you access as they see fit.
""" % settings
            else:
                settings['access_limit'] = "private"
                settings['login_info'] = """
These %(access_limit)s pages use your certificate for login. This means that
you just need to click [/login login] to ''automatically'' sign in with your
certificate ID.

Owners of a %(_label)s can login and access the [/admin Admin] menu where they
can configure fine grained access permissions for all other users with access
to the tracker.

Please contact the owners of this %(_label)s if you require greater tracker
access.
""" % settings
            intro_text = \
                       """= %(cap_kind)s %(vgrid_name)s Project Tracker =
Welcome to the ''%(access_limit)s'' %(kind)s project management site for the
'''%(vgrid_name)s''' %(_label)s. It interfaces with the corresponding code
repository for the %(_label)s and provides a number of tools to help software
development and project management.

== Quick Intro ==
This particular page is a Wiki page which means that all ''authorized''
%(vgrid_name)s users can edit it.

Generally wou need to [/login login] at the top of the page to get access to
most of the features here. The navigation menu provides buttons to access
 * this [/wiki Wiki] with customizable contents
 * a [/roadmap Project Roadmap] with goals and progress
 * the [/browser Code Browser] with access to the %(kind)s SCM repository
 * the [/report Ticket Overview] page with pending tasks or issues
 * ... and so on.
%(login_info)s

== Look and Feel ==
The look and feel of this project tracker can be customized with ordinary CSS
through the %(css_wikipage)s Wiki page. Simply create that page and go
ahead with style changes as you see fit.

== Limitations ==
For security reasons all project trackers are quite locked down to avoid abuse.
This implies a number of restrictions on the freedom to fully tweak them e.g.
by installing additional plugins or modifying the core configuration.  

== Further Information ==
Please see TitleIndex for a complete list of local wiki pages or refer to
TracIntro for additional information and help on using Trac.
""" % settings
            style_text = """/*
CSS settings for %(cap_kind)s %(vgrid_name)s project tracker.
Uncomment or add your style rules below to modify the look and feel of all the
tracker pages. The example rules target the major page sections, but you can
view the full page source to find additional style targets.
*/

/*
body {
  background: #ccc;
  background: transparent url('/images/pattern.png');
  color: #000;
  margin: 0;
  padding: 0;
}

#banner,#main,#footer {
  background: white;
  border: 1px solid black;
  border-radius: 4px;
  -moz-border-radius: 4px;
  padding: 8px;
  margin: 4px;
}

#main {
  /* Prevent footer overlap with menu */
  min-height: 500px;
}

#ctxnav,#mainnav {
  margin: 4px;
}

#header {
}

#logo img {
}
*/
""" % settings
            trac_fd, wiki_fd = NamedTemporaryFile(), NamedTemporaryFile()
            style_fd = NamedTemporaryFile()
            trac_tmp, wiki_tmp = trac_fd.name, wiki_fd.name
            style_tmp = style_fd.name
            trac_fd.close()
            wiki_fd.write(intro_text)
            wiki_fd.flush()
            style_fd.write(style_text)
            style_fd.flush()

            for (act, page, path) in [('export', 'WikiStart', trac_tmp),
                                      ('import', 'TracIntro', trac_tmp),
                                      ('import', 'WikiStart', wiki_tmp),
                                      ('import', 'SiteStyle', style_tmp)]:
                wiki_cmd = [configuration.trac_admin_path, target_tracker_var,
                            'wiki', act, page, path]
                logger.info('wiki %s %s: %s' % (act, page, wiki_cmd))
                proc = subprocess.Popen(wiki_cmd, stdout=subprocess.PIPE,
                                        stderr=subprocess.STDOUT)
                proc.wait()
                if proc.returncode != 0:
                    raise Exception("tracker wiki %s failed: %s (%d)" % \
                                    (perms_cmd, proc.stdout.read(),
                                     proc.returncode))

            wiki_fd.close()

        # Some plugins require DB changes so we always force DB update here
        # Upgrade environment using trac-admin command:
        # trac-admin tracker_dir upgrade
        upgrade_cmd = [configuration.trac_admin_path, target_tracker_var,
                       'upgrade']
        logger.info('upgrade project tracker database: %s' % upgrade_cmd)
        proc = subprocess.Popen(upgrade_cmd, stdout=subprocess.PIPE,
                                stderr=subprocess.STDOUT, env=admin_env)
        proc.wait()
        if proc.returncode != 0:
            raise Exception("tracker 2nd upgrade db %s failed: %s (%d)" % \
                            (upgrade_cmd, proc.stdout.read(),
                             proc.returncode))

        if repair:
            # Touch WSGI scripts to force reload of running instances
            for name in os.listdir(target_tracker_wsgi_link):
                os.utime(os.path.join(target_tracker_wsgi_link, name), None)
    except Exception, exc:
        create_status = False
        logger.error('create %s tracker failed: %s' % \
                     (configuration.site_vgrid_label, exc))
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Could not create %s tracker: %s'
                               % (configuration.site_vgrid_label, exc)})
예제 #7
0
파일: extcert.py 프로젝트: heromod/migrid
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        require_user=False
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s certificate sign up' % configuration.short_title
    title_entry['skipmenu'] = True
    form_fields = ['cert_id', 'cert_name', 'organization', 'email', 'country', 'state',
                   'comment']
    title_entry['style'] = themed_styles(configuration)
    title_entry['javascript'] = cert_js_helpers(form_fields)
    output_objects.append({'object_type': 'html_form',
                           'text':'''
 <div id="contextual_help">
  <div class="help_gfx_bubble"><!-- graphically connect field with help text--></div>
  <div class="help_message"><!-- filled by js --></div>
 </div>
'''                       })
    header_entry = {'object_type': 'header', 'text'
                    : 'Welcome to the %s certificate sign up page' % \
                    configuration.short_title}
    output_objects.append(header_entry)
    
    # Redirect to reqcert page without certificate requirement but without
    # changing access method (CGI vs. WSGI).
    
    certreq_url = os.environ['REQUEST_URI'].replace('-bin', '-sid')
    certreq_url = os.path.join(os.path.dirname(certreq_url), 'reqcert.py')
    certreq_link = {'object_type': 'link', 'destination': certreq_url,
                    'text': 'Request a new %s certificate' % \
                            configuration.short_title }
    new_user = distinguished_name_to_user(client_id)

    # If cert auto create is on, add user without admin interaction

    if configuration.auto_add_cert_user == False:
        extcertaction = 'extcertaction.py' 
    else:
        extcertaction = 'autocreate.py'

    output_objects.append({'object_type': 'html_form', 'text'
                          : """
This page is used to sign up for %(site)s with an existing certificate from a Certificate Authority (CA) allowed for %(site)s.
You can use it if you already have a x509 certificate from another accepted CA. In this way you can simply use your existing certificate for %(site)s access instead of requesting a new one.
<br />
The page tries to auto load any certificate your browser provides and fill in the fields accordingly, but in case it can't guess all <span class=mandatory>mandatory</span> fields, you still need to fill in those.<br />
Please enter any missing information below and press the Send button to submit the external certificate sign up request to the %(site)s administrators.
<p class='criticaltext highlight_message'>IMPORTANT: Please help us verify your identity by providing Organization and Email data that we can easily validate!<br />
That is, if You're a student/employee at KU, please enter institute acronym (NBI, DIKU, etc.) in the Organization field and use your corresponding [email protected] or USER@*.ku.dk address in the Email field.</p>
<hr />
<div class=form_container>
<!-- use post here to avoid field contents in URL -->
<form method=post action=%(extcertaction)s onSubmit='return validate_form();'>
<table>
<tr><td class='mandatory label'>Certificate DN</td><td><input id='cert_id_field' type=text size=%(dn_max_len)s maxlength=%(dn_max_len)s name=cert_id value='%(client_id)s' /></td><td class=fill_space></td></tr>
<tr><td class='mandatory label'>Full name</td><td><input id='cert_name_field' type=text name=cert_name value='%(common_name)s' /></td><td class=fill_space></td></tr>
<tr><td class='mandatory label'>Email address</td><td><input id='email_field' type=text name=email value='%(email)s' /></td><td class=fill_space></td></tr>
<tr><td class='mandatory label'>Organization</td><td><input id='organization_field' type=text name=org value='%(org)s' /></td><td class=fill_space></td></tr>
<tr><td class='mandatory label'>Two letter country-code</td><td><input id='country_field' type=text name=country maxlength=2 value='%(country)s' /></td><td class=fill_space></td></tr>
<tr><td class='optional label'>State</td><td><input id='state_field' type=text name=state value='%(state)s' /></td><td class=fill_space></td></tr>
<tr><td class='optional label'>Comment or reason why you should<br />be granted a %(site)s certificate:</td><td><textarea id='comment_field' rows=4 name=comment></textarea></td><td class=fill_space></td></tr>
<tr><td class='label'><!-- empty area --></td><td><input id='submit_button' type='submit' value='Send' /></td><td class=fill_space></td></tr>
</table>
</form>
</div>
<!-- Hidden help text -->
<div id='help_text'>
  <div id='cert_id_help'>Must be the exact Distinguished Name (DN) of your certificate</div>
  <div id='cert_name_help'>Your full name, restricted to the characters in '%(valid_name_chars)s'</div>
  <div id='organization_help'>Organization name or acronym  matching email</div>
  <div id='email_help'>Email address associated with your organization if at all possible</div>
  <div id='country_help'>Country code of your organization and on the form DE/DK/GB/US/.. , <a href='http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.html'>help</a></div>
  <div id='state_help'>Optional state of your organization, please just leave empty unless it is in the US or similar</div>
  <div id='comment_help'>Optional, but a short informative comment may help us verify your certificate needs and thus speed up our response.</div>
</div>
"""
                           % {
        'extcertaction': extcertaction,
        'valid_name_chars': valid_name_chars,
        'client_id': client_id,
        'dn_max_len': dn_max_len,
        'common_name': new_user.get('full_name', ''),
        'org': new_user.get('organization', ''),
        'email': new_user.get('email', ''),
        'state': new_user.get('state', ''),
        'country': new_user.get('country', ''),
        'site': configuration.short_title,
        }})

    return (output_objects, returnvalues.OK)
예제 #8
0
        sys.exit(1)

    if args:
        user_dict['full_name'] = args[0]
        try:
            user_dict['organization'] = args[1]
            user_dict['state'] = args[2]
            user_dict['country'] = args[3]
            user_dict['email'] = args[4]
        except IndexError:

            # Ignore missing optional arguments

            pass
    elif user_id:
        user_dict = distinguished_name_to_user(user_id)
    else:
        print 'Please enter the details for the user to be removed:'
        user_dict['full_name'] = raw_input('Full Name: ').title()
        user_dict['organization'] = raw_input('Organization: ')
        user_dict['state'] = raw_input('State: ')
        user_dict['country'] = raw_input('2-letter Country Code: ')
        user_dict['email'] = raw_input('Email: ')

    if not user_dict.has_key('distinguished_name'):
        fill_distinguished_name(user_dict)

    fill_user(user_dict)

    # Now all user fields are set and we can begin deleting the user
예제 #9
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    output_objects.append({'object_type': 'header', 'text'
                          : '%s external certificate sign up' % \
                            configuration.short_title })

    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        require_user=False
        )
    if not validate_status:
        logger.warning('%s invalid input: %s' % (op_name, accepted))
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    admin_email = configuration.admin_email
    smtp_server = configuration.smtp_server
    user_pending = os.path.abspath(configuration.user_pending)

    cert_id = accepted['cert_id'][-1].strip()

    # force name to capitalized form (henrik karlsen -> Henrik Karlsen)
    # please note that we get utf8 coded bytes here and title() treats such
    # chars as word termination. Temporarily force to unicode.

    raw_name = accepted['cert_name'][-1].strip() 
    try:
        cert_name = force_utf8(force_unicode(raw_name).title())
    except Exception:
        cert_name = raw_name.title()
    country = accepted['country'][-1].strip().upper()
    state = accepted['state'][-1].strip().title()
    org = accepted['org'][-1].strip()

    # lower case email address

    email = accepted['email'][-1].strip().lower()

    # keep comment to a single line

    comment = accepted['comment'][-1].replace('\n', '   ')

    # single quotes break command line format - remove

    comment = comment.replace("'", ' ')

    is_diku_email = False
    is_diku_org = False
    if email.find('@diku.dk') != -1:
        is_diku_email = True
    if 'DIKU' == org.upper():

        # Consistent upper casing

        org = org.upper()
        is_diku_org = True

    if is_diku_org != is_diku_email:
        output_objects.append({'object_type': 'error_text', 'text'
                              : '''Illegal email and organization combination:
Please read and follow the instructions in red on the request page!
If you are a DIKU student with only a @*.ku.dk address please just use KU as
organization.
As long as you state that you want the certificate for DIKU purposes in the
comment field, you will be given access to the necessary resources anyway.
'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    try:
        distinguished_name_to_user(cert_id)
    except:
        output_objects.append({'object_type': 'error_text', 'text'
                              : '''Illegal Distinguished name:
Please note that the distinguished name must be a valid certificate DN with
multiple "key=val" fields separated by "/".
'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    user_dict = {
        'distinguished_name': cert_id,
        'full_name': cert_name,
        'organization': org,
        'state': state,
        'country': country,
        'email': email,
        'password': '',
        'comment': '%s: %s' % ('Existing certificate', comment),
        'expire': int(time.time() + cert_valid_days * 24 * 60 * 60),
        'openid_names': [],
        }
    fill_distinguished_name(user_dict)
    user_id = user_dict['distinguished_name']
    if configuration.user_openid_providers and configuration.user_openid_alias:
        user_dict['openid_names'] += \
                                  [user_dict[configuration.user_openid_alias]]
    logger.info('got extcert request: %s' % user_dict)

    # If server allows automatic addition of users with a CA validated cert
    # we create the user immediately and skip mail
    
    if configuration.auto_add_cert_user:
        fill_user(user_dict)

        # Now all user fields are set and we can begin adding the user

        db_path = os.path.join(configuration.mig_server_home, user_db_filename)
        try:
            create_user(user_dict, configuration.config_file, db_path,
                        ask_renew=False)
        except Exception, err:
            logger.error('Failed to create user with existing cert %s: %s'
                     % (cert_id, err))
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : '''Could not create the user account for you:
Please report this problem to the grid administrators (%s).''' % \
                 admin_email})
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({'object_type': 'text', 'text'
                                   : '''Created the user account for you:
Please use the navigation menu to the left to proceed using it.
'''})
        return (output_objects, returnvalues.OK)