Exemple #1
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/...) either in
    tags or in plain text line.
    """

    users = []
    for user_creds in re.findall('/[a-zA-Z]+=[^<\n]+', user_data):
        #print "DEBUG: handling user %s" % user_creds
        user_dict = distinguished_name_to_user(user_creds.strip())
        users.append(user_dict)
    return users
Exemple #2
0
def rm_tracker_admin(configuration, cert_id, vgrid_name, tracker_dir,
                     output_objects):
    """Remove Trac issue tracker owner"""
    _logger = configuration.logger
    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)

    # Trac requires tweaking for certain versions of setuptools
    # http://trac.edgewall.org/wiki/setuptools
    admin_env = {}
    # strip non-string args from env to avoid wsgi execv errors like
    # http://stackoverflow.com/questions/13213676
    for (key, val) in os.environ.items():
        if isinstance(val, basestring):
            admin_env[key] = val
    admin_env["PKG_RESOURCES_CACHE_ZIP_MANIFESTS"] = "1"

    try:
        admin_user = distinguished_name_to_user(cert_id)
        admin_id = admin_user.get(configuration.trac_id_field, 'unknown_id')
        # Remove admin rights for owner using trac-admin command:
        # trac-admin tracker_dir deploy cgi_tracker_bin
        perms_cmd = [configuration.trac_admin_path, cgi_tracker_var,
                     'permission', 'remove', admin_id, 'TRAC_ADMIN']
        _logger.info('remove admin rights from owner: %s' % perms_cmd)
        # NOTE: we use command list here to avoid shell requirement
        proc = subprocess_popen(perms_cmd, stdout=subprocess_pipe,
                                stderr=subprocess_stdout, env=admin_env)
        retval = proc.wait()
        if retval != 0:
            out = proc.stdout.read()
            if out.find("user has not been granted the permission") != -1:
                _logger.warning(
                    "ignore missing Trac admin for legacy user %s" % admin_id)
            else:
                raise Exception("tracker permissions %s failed: %s (%d)" %
                                (perms_cmd, out, retval))
        return True
    except Exception, exc:
        output_objects.append(
            {'object_type': 'error_text', 'text':
             'Could not remove %s tracker admin rights: %s' % (cert_id, exc)
             })
        return False
Exemple #3
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)
    elif not configuration.site_enable_gdp:
        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: ')
    else:
        print "Error: Missing one or more of the arguments: " \
            + "[FULL_NAME] [ORGANIZATION] [STATE] [COUNTRY] " \
            + "[EMAIL]"
        sys.exit(1)

    if not user_dict.has_key('distinguished_name'):
        fill_distinguished_name(user_dict)
Exemple #4
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)

    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("'", ' ')

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    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': [],
        'auth': ['extcert'],
    }
    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)
Exemple #5
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, 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)

    if not configuration.site_enable_openid or \
            not 'migoid' in configuration.site_signup_methods:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Local OpenID login is not enabled on this site'''
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s OpenID account request' % \
                          configuration.short_title
    title_entry['skipmenu'] = True
    form_fields = [
        'full_name', 'organization', 'email', 'country', 'state', 'password',
        'verifypassword', 'comment'
    ]
    title_entry['style']['advanced'] += account_css_helpers(configuration)
    add_import, add_init, add_ready = account_js_helpers(
        configuration, form_fields)
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    title_entry['script']['body'] = "class='staticpage'"

    header_entry = {
        'object_type':
        'header',
        'text':
        'Welcome to the %s OpenID account request page' %
        configuration.short_title
    }
    output_objects.append(header_entry)

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '''
    <div id="contextual_help">

    </div>
'''
    })

    # 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 %s User OpenID you can still request one below:''' %
            (configuration.short_title, configuration.user_mig_oid_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 valid %s credentials, but if you want to add %s
User OpenID access to the same account you can do so by posting the form below.
Changing fields is <span class="warningtext"> not </span> supported, so all fields
must remain unchanged for it to work.
Otherwise it results in a request for a new account and OpenID without access
to your old files, jobs and privileges. </p>''' %
            (configuration.short_title, configuration.user_mig_oid_title)
        })
        user_fields.update(distinguished_name_to_user(client_id))

    # Site policy dictates min length greater or equal than password_min_len
    policy_min_len, policy_min_classes = parse_password_policy(configuration)
    user_fields.update({
        'valid_name_chars':
        '%s (and common accents)' % html_escape(valid_name_chars),
        'valid_password_chars':
        html_escape(valid_password_chars),
        'password_min_len':
        max(policy_min_len, password_min_len),
        'password_max_len':
        password_max_len,
        'password_min_classes':
        max(policy_min_classes, 1),
        'site':
        configuration.short_title
    })
    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }
    target_op = 'reqoidaction'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token})

    fill_helpers.update({'site_signup_hint': configuration.site_signup_hint})
    fill_helpers.update(user_fields)
    html = """
<p class="sub-title">Please enter your information in at least the <span>mandatory</span> fields below and press the Send button to submit the OpenID account request to the %(site)s administrators.</p>

%(site_signup_hint)s

<p class='criticaltext highlight_message'>
IMPORTANT: Please help us verify your identity by providing Organization and
Email data that we can easily validate!
</p>

<hr />

    """
    user_country = user_fields.get('country', '')
    html += account_request_template(configuration,
                                     default_country=user_country)

    # TODO: remove this legacy version?
    html += """
<div style="height: 0; visibility: hidden; display: none;">
<!--OLD FORM-->
<form method='%(form_method)s' action='%(target_op)s.py' onSubmit='return validate_form();'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />


<table>
<!-- NOTE: javascript support for unicode pattern matching is lacking so we
           only restrict e.g. Full Name to words separated by space here. The
           full check takes place in the backend, but users are better of with
           sane early warnings than the cryptic backend errors.
-->

<tr><td class='mandatory label'>Full name</td><td><input id='full_name_field' type=text name=cert_name value='%(full_name)s' required pattern='[^ ]+([ ][^ ]+)+' title='Your full name, i.e. two or more names separated by space' /></td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Email address</td><td><input id='email_field' type=email name=email value='%(email)s' required title='A valid email address that you read' /> </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' required pattern='[^ ]+([ ][^ ]+)*' title='Name of your organisation: one or more abbreviations or words separated by space' /></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 minlength=2 maxlength=2 value='%(country)s' required pattern='[A-Z]{2}' title='The two capital letters used to abbreviate your country' /></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' pattern='([A-Z]{2})?' maxlength=2 title='Leave empty or enter the capital 2-letter abbreviation of your state if you are a US resident' /> </td><td class=fill_space><br /></td></tr>
<tr><td class='mandatory label'>Password</td><td><input id='password_field' type=password name=password minlength=%(password_min_len)d maxlength=%(password_max_len)d value='%(password)s' required pattern='.{%(password_min_len)d,%(password_max_len)d}' title='Password of your choice, see help box for limitations' /> </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 minlength=%(password_min_len)d maxlength=%(password_max_len)d value='%(verifypassword)s' required pattern='.{%(password_min_len)d,%(password_max_len)d}' title='Repeat your chosen password' /></td><td class=fill_space><br /></td></tr>
<!-- NOTE: we technically allow saving the password on scrambled form hide it by default -->
<tr class='hidden'><td class='optional label'>Password recovery</td><td class=''><input id='passwordrecovery_checkbox' type=checkbox name=passwordrecovery></td>
</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 account:</td><td><textarea id='comment_field' rows=4 name=comment title='A free-form comment where you can explain what you need the account for' ></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>
<hr />
<div class='warn_message'>Please note that if you enable password recovery your password will be saved on encoded format but recoverable by the %(site)s administrators</div>
</div>
<br />
<br />
<!-- Hidden help text -->
<div id='help_text'>
  <div id='1full_name_help'>Your full name, restricted to the characters in '%(valid_name_chars)s'</div>
  <div id='1organization_help'>Organization name or acronym  matching email</div>
  <div id='1email_help'>Email address associated with your organization if at all possible</div>
  <div id='1country_help'>Country code of your organization and on the form DE/DK/GB/US/.. , <a href='https://en.wikipedia.org/wiki/ISO_3166-1'>help</a></div>
  <div id='1state_help'>Optional 2-letter ANSI state code of your organization, please just leave empty unless it is in the US or similar, <a href='https://en.wikipedia.org/wiki/List_of_U.S._state_abbreviations'>help</a></div>
  <div id='1password_help'>Password is restricted to the characters:<br/><tt>%(valid_password_chars)s</tt><br/>Certain other complexity requirements apply for adequate strength. For example it must be %(password_min_len)s to %(password_max_len)s characters long and contain at least %(password_min_classes)d different character classes.</div>
  <div id='1verifypassword_help'>Please repeat password</div>
  <!--<div id='1comment_help'>Optional, but a short informative comment may help us verify your account needs and thus speed up our response. Typically the name of a local collaboration partner or project may be helpful.</div>-->
</div>

"""

    output_objects.append({
        'object_type': 'html_form',
        'text': html % fill_helpers
    })
    return (output_objects, returnvalues.OK)
Exemple #6
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)
    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 account sign up' % \
                          configuration.short_title
    title_entry['skipmenu'] = True
    form_fields = ['cert_id', 'cert_name', 'organization', 'email', 'country',
                   'state', 'comment']
    title_entry['style']['advanced'] += account_css_helpers(configuration)
    add_import, add_init, add_ready = account_js_helpers(configuration,
                                                         form_fields)
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    title_entry['script']['body'] = "class='staticpage'"
#    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 account 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 account' %
                            configuration.short_title}
    new_user = distinguished_name_to_user(client_id)

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

    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {'valid_name_chars': valid_name_chars,
                    'client_id': client_id,
                    'dn_max_len': dn_max_len,
                    'full_name': new_user.get('full_name', ''),
                    'organization': new_user.get('organization', ''),
                    'email': new_user.get('email', ''),
                    'state': new_user.get('state', ''),
                    'country': new_user.get('country', ''),
                    'site': configuration.short_title,
                    'form_method': form_method,
                    'csrf_field': csrf_field,
                    'csrf_limit': csrf_limit}
    if configuration.auto_add_cert_user == False:
        target_op = 'extcertaction'
    else:
        target_op = 'autocreate'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token})
    fill_helpers.update({'site_signup_hint': configuration.site_signup_hint})

    html = """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!
</p>
%(site_signup_hint)s
<hr />
"""

    html += account_request_template(configuration, password=False)

    # TODO : remove this legacy version?
    html += """
<div style="height: 0; visibility: hidden; display: none;">
<!--OLD FORM-->
<div class=form_container>
<!-- use post here to avoid field contents in URL -->
<form method='%(form_method)s' action='%(target_op)s.py' onSubmit='return validate_form();'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<table>
<!-- NOTE: javascript support for unicode pattern matching is lacking so we
           only restrict e.g. Full Name to words separated by space here. The
           full check takes place in the backend, but users are better of with
           sane early warnings than the cryptic backend errors.
-->
<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' required pattern='(/[a-zA-Z]+=[^/ ]+([ ][^/ ]+)*)+' title='The Distinguished Name field of your certificate, i.e. key=value pairs separated by slashes' /></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='%(full_name)s' required pattern='[^ ]+([ ][^ ]+)+' title='Your full name, i.e. two or more names separated by space' /></td><td class=fill_space></td></tr>
<tr><td class='mandatory label'>Email address</td><td><input id='email_field' type=email name=email value='%(email)s' title='A valid email address that you read' /></td><td class=fill_space></td></tr>
<tr><td class='mandatory label'>Organization</td><td><input id='organization_field' type=text name=org value='%(organization)s' required pattern='[^ ]+([ ][^ ]+)*' title='Name of your organisation: one or more abbreviations or words separated by space' /></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 minlength=2 maxlength=2 value='%(country)s' required pattern='[A-Z]{2}' title='The two capital letters used to abbreviate your country' /></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' pattern='([A-Z]{2})?' maxlength=2 title='Leave empty or enter the capital 2-letter abbreviation of your state if you are a US resident' /></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 title='A free-form comment where you can explain what you need the certificate for'></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='https://en.wikipedia.org/wiki/ISO_3166-1'>help</a></div>
  <div id='state_help'>Optional 2-letter ANSI state code of your organization, please just leave empty unless it is in the US or similar, <a href='https://en.wikipedia.org/wiki/List_of_U.S._state_abbreviations'>help</a></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>
</div>
    """
    output_objects.append({'object_type': 'html_form', 'text':
                           html % fill_helpers})

    return (output_objects, returnvalues.OK)
Exemple #7
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)
    req_url = environ['SCRIPT_URI']
    if client_id and client_id == identity:
        login_type = 'cert'
        if req_url.startswith(configuration.migserver_https_mig_cert_url):
            base_url = configuration.migserver_https_mig_cert_url
        elif req_url.startswith(configuration.migserver_https_ext_cert_url):
            base_url = configuration.migserver_https_ext_cert_url
        else:
            logger.warning('no match for cert request URL: %s' % req_url)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'No matching request URL: %s' % req_url
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)
    elif identity:
        login_type = 'oid'
        if req_url.startswith(configuration.migserver_https_mig_oid_url):
            base_url = configuration.migserver_https_mig_oid_url
        elif req_url.startswith(configuration.migserver_https_ext_oid_url):
            base_url = configuration.migserver_https_ext_oid_url
        else:
            logger.warning('no match for oid request URL: %s' % req_url)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'No matching request URL: %s' % req_url
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)
        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 safe_handler(
            configuration, 'post', op_name, client_id,
            get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only
accepting CSRF-filtered 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])
        association = ','.join([i for i in accepted['association'] 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 and associations

        role = ','.join([i for i in accepted['openid.sreg.role'] if i])
        association = ','.join(
            [i for i in accepted['openid.sreg.association'] if i])
        locality = accepted['openid.sreg.locality'][-1].strip()
        timezone = accepted['openid.sreg.timezone'][-1].strip()

        # We may encounter results without an email, fall back to uniq_id then

        email = accepted['openid.sreg.email'][-1].strip() or uniq_id

    # 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.
        # Additionally in the special case with unknown institute (ou=ukendt)
        # we force organization to KU to align with cert policies.
        # 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'
            if org == 'UKENDT':
                org = 'KU'
                logger.info('unknown affilition, set organization to %s' % org)

        # Stay on virtual host - extra useful while we test dual OpenID

        if configuration.site_enable_gdp:
            base_url = environ.get('REQUEST_URI',
                                   base_url).split('?')[0].replace(
                                       'autocreate', 'gdpman')
        else:
            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,
        'association': association,
        '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:
        if accepted.get('openid.sreg.required', '') and identity:
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                '''<p class="spinner iconleftpad">
Auto log out first to avoid sign up problems ...
</p>'''
            })
            html = \
                """
            <a id='autologout' href='%s'></a>
            <script type='text/javascript'>
                document.getElementById('autologout').click();
            </script>""" \
                % openid_autologout_url(configuration, identity,
                    client_id, req_url, user_arguments_dict)
            output_objects.append({'object_type': 'html_form', 'text': html})
        return (output_objects, returnvalues.CLIENT_ERROR)

    auth = 'unknown'
    if login_type == 'cert':
        auth = 'extcert'
        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':
        auth = 'extoid'
        user_dict['expire'] = int(time.time() + oid_valid_days * 24 * 60 * 60)
        fill_distinguished_name(user_dict)
        uniq_id = user_dict['distinguished_name']

    # Save auth access method

    user_dict['auth'] = [auth]

    # 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)

        logger.info('created user account for %s' % uniq_id)
        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)
Exemple #8
0
remote_addr = ''
print sys.argv
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]
if sys.argv[5:]:
    remote_user = sys.argv[5]
if sys.argv[6:]:
    remote_addr = sys.argv[6]
if sys.argv[7:]:
    auto_csrf = (sys.argv[7].lower() in ('yes', 'true'))

run_as_user = distinguished_name_to_user(run_as_dn)

if method.lower() == 'post' and auto_csrf:
    configuration = get_configuration_object()
    form_method = method.lower()
    client_id = run_as_dn
    csrf_limit = get_csrf_limit(configuration)
    target_op = os.path.splitext(os.path.basename(script))[0]
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    query += ";%s=%s" % (csrf_field, csrf_token)

extra_environment = {
    'REQUEST_METHOD': method,
    'SERVER_PROTOCOL': 'HTTP/1.1',
    'GATEWAY_INTERFACE': 'CGI/1.1',