Пример #1
0
    def __init__(self, config, primary_ator, server_section_name):
        log.msg(
            'RADIUS PEAP/EAP-GTC Automatic Factor Server Module Configuration:'
        )
        log.config(
            config, lambda x: x.startswith('radius_secret') or x in
            ('skey', 'skey_protected'))

        self.protocol = DuoEAPRadiusServer(
            secrets=parse_radius_secrets(config),
            primary_ator=primary_ator,
            duo_client=self.make_duo_client(config),
            failmode=config.get_enum('failmode',
                                     duo_async.FAILMODES,
                                     duo_async.FAILMODE_SAFE,
                                     transform=str.lower),
            factors=util.parse_factor_list(config.get_str('factors', 'auto')),
            delim=config.get_str('delimiter', ','),
            delimited_password_length=config.get_int(
                'delimited_password_length', 0),
            allow_concat=config.get_bool('allow_concat', False),
            debug=config.get_bool('debug', False),
            pass_through_attr_names=config.get_str('pass_through_attr_names',
                                                   ''),
            prompt=config.get_str('prompt', 'Enter your password: '******'pkey'),
            cert_file=config.get_str('certs'),
            cipher_list=config.get_str('cipher_list', ''),
            minimum_tls_version=config.get_str('minimum_tls_version', ''),
            pw_codec=config.get_str('pw_codec', 'utf-8'),
            client_ip_attr=parse_client_ip_attribute(config),
            server_section_name=server_section_name,
            pass_through_all=config.get_bool('pass_through_all', False),
        )
Пример #2
0
    def __init__(self, config, primary_client, server_section_name):
        log.msg("RADIUS IFrame Server Module Configuration:")
        log.config(
            config,
            lambda x: x.startswith("radius_secret") or x in
            ("skey", "skey_protected"),
        )

        failmode = config.get_enum(
            "failmode",
            duo_async.FAILMODES,
            duo_async.FAILMODE_SAFE,
            transform=str.lower,
        )
        secrets = parse_radius_secrets(config)
        type = config.get_enum("type", JS_TYPES)

        if type != JS_TYPE_CITRIX:
            api_timeout = 15
        else:
            # citrix devices don't retransmit correctly,
            # and can't do timeouts > 10 seconds
            api_timeout = 8
        duo_client = self.make_duo_client(config, default_timeout=api_timeout)

        # script injection snippet, js file
        script_file_default = SCRIPT_FILES[type]
        if duo_client.port == 443:
            script_uri_default = "https://%s/frame/hosted/%s" % (
                duo_client.host,
                script_file_default,
            )
        else:
            script_uri_default = "https://%s:%d/frame/hosted/%s" % (
                duo_client.host,
                duo_client.port,
                script_file_default,
            )
        script_uri = config.get_str("iframe_script_uri", script_uri_default)
        script_inject_default = SCRIPT_INJECT[type]
        script_inject = config.get_str("script_inject", script_inject_default)

        self.protocol = DuoIFrameRadiusServer(
            type,
            script_uri,
            script_inject,
            failmode,
            duo_client=duo_client,
            exempt_usernames=parse_exempt_usernames(config),
            secrets=secrets,
            primary_ator=primary_client,
            pass_through_attr_names=config.get_str("pass_through_attr_names",
                                                   ""),
            pass_through_all=config.get_bool("pass_through_all", False),
            pw_codec=config.get_str("pw_codec", "utf-8"),
            client_ip_attr=parse_client_ip_attribute(config),
            server_section_name=server_section_name,
            server_section_ikey=config.get_str("ikey", ""),
        )
Пример #3
0
def create_application(args=None, twistd_user=None, log_group=None):
    home_dir = util.get_home_dir()
    os.chdir(home_dir)
    is_logging_insecure = False

    # parse command-line args, if appropriate
    primary_only_time = None
    if args:
        option_parser = argparse.ArgumentParser()

        option_parser.add_argument(
            "--primary-only",
            type=int,
            nargs="?",
            help=
            "This option disables secondary authentication for the specified number of minutes (default 60)",
            default=None,
            const=60,
        )
        option_parser.add_argument(
            "--logging-insecure",
            action="store_true",
            help=
            "This option enables debug, and prints logs containing passwords and possibly other secrets.",
            default=False,
        )
        options = option_parser.parse_args()
        is_logging_insecure = options.logging_insecure
        primary_only_time = options.primary_only

    config_filename = os.path.join("conf", "authproxy.cfg")
    configuration = config_provider.get_config(config_filename)

    if primary_only_time is not None:
        if primary_only_time > 240:
            print(
                "Primary only mode can only be enabled for a maximum of 4 hours (240 minutes)"
            )
            sys.exit(2)
        else:
            PrimaryOnlyManager.enable_primary_only(primary_only_time)

    main_config = configuration.get_main_section_config()
    if main_config:
        log.msg("Main Configuration:")
        log.config(main_config)

    fips_mode = main_config.get_bool("fips_mode", False)
    if fips_mode:
        fips_manager.enable()

    # Set up our observers
    if is_logging_insecure:
        observers = [textFileLogObserver(sys.stdout)]
    else:
        observers = log_observation.get_observers(main_config, twistd_user,
                                                  log_group)

    for observer in observers:
        globalLogPublisher.addObserver(observer)

    # Global debug mode
    if is_logging_insecure:
        debug_mode = True
    else:
        debug_mode = main_config.get_bool("debug", False)

    http.set_debug(debug_mode)
    http.set_is_logging_insecure(is_logging_insecure)

    # Create main application.
    application = Application("duoauthproxy")
    LogReadyService().setServiceParent(application)

    fips_mode = fips_manager.status()
    if fips_mode:
        log.msg("FIPS mode {0} is enabled with {1}".format(
            fips_mode, fips_manager.get_openssl_version()))
    else:
        log.msg("FIPS mode is not enabled")

    # get ca certs file
    http_ca_certs_file = main_config.get_str("http_ca_certs_file", "")
    if http_ca_certs_file:
        http_ca_certs_file = util.resolve_file_path(http_ca_certs_file)
    else:
        http_ca_certs_file = os.path.join("conf",
                                          const.DEFAULT_HTTP_CERTS_FILE)

    # read ca certs
    if not os.path.isfile(http_ca_certs_file):
        http_ca_certs_file = os.path.join("conf", http_ca_certs_file)
    with open(http_ca_certs_file, "r") as bundle_fp:
        http.set_ca_certs(ssl_verify.load_ca_bundle(bundle_fp))

    # get proxy settings
    http_proxy_host = main_config.get_str("http_proxy_host", "")
    http_proxy_port = main_config.get_int("http_proxy_port", 80)
    if http_proxy_host:
        http.set_proxy(http_proxy_host, http_proxy_port)

    sections = section.parse_sections(configuration, is_logging_insecure)
    module_factory = section.ModuleFactory(sections, application)
    modules_by_type = module_factory.make_modules()

    if not any(modules_by_type.values()):
        raise config_error.ConfigError("No integrations in config file.")

    # Setup forwarding/server pairs by port
    for port, interface in modules_by_type.get("server", []):
        server_networks = {}
        server_names = {}
        for section_name, server_module, server_config in modules_by_type[
                "server"][(port, interface)]:
            client_name = configuration.get_section_client(section_name)

            if not client_name:
                if server_module.Module.no_client:
                    modules_by_type["client"]["no_client"] = None
                    client_name = "no_client"
                else:
                    raise config_error.ConfigError(
                        'Neither module %s or main has "client" value' %
                        section_name)

            if section_name.startswith(
                    "ldap_server_auto"
            ) and not client_name.startswith("ad_client"):
                raise config_error.ConfigError(
                    "ad_client is required by ldap_server_auto. No ad_client found in config file. "
                )

            if client_name != "radius_client" and server_config.get_str(
                    "pass_through_attr_names", ""):
                raise config_error.ConfigError(
                    "Can only pass through radius attributes if using a radius client"
                )
            server_instance = server_module.Module(
                server_config, modules_by_type["client"][client_name],
                section_name)
            server_instance.setServiceParent(application)

            if section_name.startswith("radius_server_"):
                server_networks[server_instance] = parse_radius_secrets(
                    server_config).keys()
                server_names[server_instance] = section_name

        if server_names:
            forward_module = forward_serv
            forward_instance = forward_module.Module(
                port=port,
                servers=server_networks,
                server_names=server_names,
                interface=interface,
                debug=debug_mode,
            )
            forward_instance.setServiceParent(application)

    # set user-agent
    sections = ",".join(sorted(set(configuration.list_sections())))
    user_agent = "duoauthproxy/{0} ({1}; Python{2}; {3})".format(
        get_version(), platform.platform(), platform.python_version(),
        sections)
    http.set_user_agent(user_agent)

    # Authproxy uses globalLogPublisher to emit events. Defining a no-op emitter will squelch the creation
    # of the unwatned twistd default logging mechanisms.
    def no_op_emitter(eventDict):
        pass

    application.setComponent(ILogObserver, no_op_emitter)

    return application
Пример #4
0
def create_application(args=None, twistd_user=None, log_group=None):
    home_dir = util.get_home_dir()
    os.chdir(home_dir)
    is_logging_insecure = False

    if syslog is not None:
        facility_dict = {
            'LOG_KERN': pySyslog.LOG_KERN,
            'LOG_USER': pySyslog.LOG_USER,
            'LOG_MAIL': pySyslog.LOG_MAIL,
            'LOG_DAEMON': pySyslog.LOG_DAEMON,
            'LOG_AUTH': pySyslog.LOG_AUTH,
            'LOG_LPR': pySyslog.LOG_LPR,
            'LOG_NEWS': pySyslog.LOG_NEWS,
            'LOG_UUCP': pySyslog.LOG_UUCP,
            'LOG_CRON': pySyslog.LOG_CRON,
            'LOG_SYSLOG': pySyslog.LOG_SYSLOG,
            'LOG_LOCAL0': pySyslog.LOG_LOCAL0,
            'LOG_LOCAL1': pySyslog.LOG_LOCAL1,
            'LOG_LOCAL2': pySyslog.LOG_LOCAL2,
            'LOG_LOCAL3': pySyslog.LOG_LOCAL3,
            'LOG_LOCAL4': pySyslog.LOG_LOCAL4,
            'LOG_LOCAL5': pySyslog.LOG_LOCAL5,
            'LOG_LOCAL6': pySyslog.LOG_LOCAL6,
            'LOG_LOCAL7': pySyslog.LOG_LOCAL7
        }

    # parse command-line args, if appropriate
    primary_only_time = None
    if args:
        option_parser = argparse.ArgumentParser()

        option_parser.add_argument(
            "--primary-only", type=int, nargs='?',
            help="This option disables secondary authentication for the specified number of minutes (default 60)",
            default=None, const=60
        )
        option_parser.add_argument(
            "--logging-insecure",
            action="store_true",
            help="This option enables debug, and prints logs containing passwords and possibly other secrets.",
            default=False
        )
        options = option_parser.parse_args()
        is_logging_insecure = options.logging_insecure
        primary_only_time = options.primary_only

    config_filename = os.path.join('conf', 'authproxy.cfg')
    configuration = config_provider.get_config(config_filename)

    if primary_only_time is not None:
        if primary_only_time > 240:
            print("Primary only mode can only be enabled for a maximum of 4 hours (240 minutes)")
            sys.exit(2)
        else:
            PrimaryOnlyManager.enable_primary_only(primary_only_time)

    main_config = configuration.get_main_section_config()
    if main_config:
        log.msg('Main Configuration:')
        log.config(main_config)

    fips_mode = main_config.get_bool('fips_mode', False)
    if fips_mode:
        fips_manager.enable()

    # handle log configuration
    log_to_file = main_config.get_bool('log_file', False)
    log_stdout = main_config.get_bool('log_stdout', False)
    log_syslog = main_config.get_bool('log_syslog', False)
    log_auth_events = main_config.get_bool('log_auth_events', False)
    log_sso_events = main_config.get_bool('log_sso_events', True)

    if is_logging_insecure:
        globalLogPublisher.addObserver(textFileLogObserver(sys.stdout))
    else:
        if log_to_file or not (log_to_file or log_syslog or log_stdout):
            log_dir = main_config.get_str('log_dir', 'log')
            log_max_size = main_config.get_int('log_max_size', 10 * (1 << 20))
            log_max_files = main_config.get_int('log_max_files', 6)
            if log_max_files == 0:
                # we need to pass None explicitly if we want there to be no limit
                # 0 would just mean no logfiles would get kept...
                log_max_files = None

            log_file = create_log_file('authproxy.log', log_dir, log_max_size,
                                       log_max_files, twistd_user, log_group)
            log_file_observer = textFileLogObserver(log_file)

            if log_auth_events:
                auth_log_file = create_log_file('authevents.log', log_dir, log_max_size, log_max_files, twistd_user, log_group)
                auth_observer = FileLogObserver(auth_log_file, log.format_auth_event)
            else:
                auth_observer = log.no_op_observer

            if log_sso_events:
                sso_log_file = create_log_file('ssoevents.log', log_dir, log_max_size, log_max_files, twistd_user, log_group)
                sso_observer = FileLogObserver(sso_log_file, log.format_sso_event)
            else:
                sso_observer = log.no_op_observer

            auth_filtering_observer = FilteringLogObserver(auth_observer,
                                                           [log.auth_type_predicate],
                                                           log.no_op_observer)

            globalLogPublisher.addObserver(auth_filtering_observer)

            sso_filtering_observer = FilteringLogObserver(sso_observer,
                                                          [log.sso_type_predicate],
                                                          log.no_op_observer)

            globalLogPublisher.addObserver(sso_filtering_observer)

            # the default authproxy.log
            log_file_observer = FilteringLogObserver(log_file_observer,
                                                     [log.only_default_log_predicate],
                                                     log.no_op_observer)

            globalLogPublisher.addObserver(log_file_observer)

        if log_stdout:
            std_out_observer = textFileLogObserver(sys.stdout)
            std_out_filter = FilteringLogObserver(log.no_op_observer,
                                                  [log.auth_type_predicate],
                                                  std_out_observer)
            globalLogPublisher.addObserver(std_out_filter)
        if log_syslog:
            if syslog is None:
                raise config_error.ConfigError('syslog not supported on Windows')
            syslog_facilitystr = main_config.get_str('syslog_facility', 'LOG_USER')
            syslog_facility = facility_dict.get(syslog_facilitystr, None)
            if syslog_facility is None:
                raise config_error.ConfigError('Unknown syslog_facility: {0}'.format(syslog_facilitystr))
            syslog_observer = syslog.SyslogObserver('Authproxy', facility=syslog_facility)
            wrapped_syslog_observer = LegacyLogObserverWrapper(syslog_observer.emit)
            syslog_filtering_observer = FilteringLogObserver(log.no_op_observer,
                                                             [log.auth_type_predicate],
                                                             wrapped_syslog_observer)
            globalLogPublisher.addObserver(syslog_filtering_observer)

    # Global debug mode
    if is_logging_insecure:
        debug_mode = True
    else:
        debug_mode = main_config.get_bool('debug', False)

    http.set_debug(debug_mode)
    http.set_is_logging_insecure(is_logging_insecure)

    # Create main application.
    application = Application('duoauthproxy')
    LogReadyService().setServiceParent(application)

    fips_mode = fips_manager.status()
    if fips_mode:
        log.msg("FIPS mode {0} is enabled with {1}".format(fips_mode, fips_manager.get_openssl_version()))
    else:
        log.msg("FIPS mode is not enabled")

    # get ca certs file
    http_ca_certs_file = main_config.get_str('http_ca_certs_file', '')
    if http_ca_certs_file:
        http_ca_certs_file = util.resolve_file_path(http_ca_certs_file)
    else:
        http_ca_certs_file = os.path.join('conf', const.DEFAULT_HTTP_CERTS_FILE)

    # read ca certs
    if not os.path.isfile(http_ca_certs_file):
        http_ca_certs_file = os.path.join('conf', http_ca_certs_file)
    with open(http_ca_certs_file, 'r') as bundle_fp:
        http.set_ca_certs(ssl_verify.load_ca_bundle(bundle_fp))

    # get proxy settings
    http_proxy_host = main_config.get_str('http_proxy_host', '')
    http_proxy_port = main_config.get_int('http_proxy_port', 80)
    if http_proxy_host:
        http.set_proxy(http_proxy_host, http_proxy_port)

    sections = section.parse_sections(configuration, is_logging_insecure)
    module_factory = section.ModuleFactory(sections, application)
    modules_by_type = module_factory.make_modules()

    if not any(modules_by_type.values()):
        raise config_error.ConfigError('No integrations in config file.')

    # Setup forwarding/server pairs by port
    for port, interface in modules_by_type.get('server', []):
        server_networks = {}
        server_names = {}
        for section_name, server_module, server_config in modules_by_type['server'][(port, interface)]:
            client_name = configuration.get_section_client(section_name)

            if not client_name:
                if server_module.Module.no_client:
                    modules_by_type['client']['no_client'] = None
                    client_name = 'no_client'
                else:
                    raise config_error.ConfigError('Neither module %s or main has "client" value' % section_name)

            if section_name.startswith('ldap_server_auto') and not client_name.startswith('ad_client'):
                raise config_error.ConfigError('ad_client is required by ldap_server_auto. No ad_client found in config file. ')

            if client_name != 'radius_client' \
                    and server_config.get_str('pass_through_attr_names', ''):
                raise config_error.ConfigError('Can only pass through radius attributes if using a radius client')
            server_instance = server_module.Module(server_config,
                                                   modules_by_type['client'][client_name],
                                                   section_name)
            server_instance.setServiceParent(application)

            if section_name.startswith('radius_server_'):
                server_networks[server_instance] = parse_radius_secrets(server_config).keys()
                server_names[server_instance] = section_name

        if server_names:
            forward_module = forward_serv
            forward_instance = forward_module.Module(
                port=port,
                servers=server_networks,
                server_names=server_names,
                interface=interface,
                debug=debug_mode,
            )
            forward_instance.setServiceParent(application)

    # set user-agent
    sections = ','.join(sorted(set(configuration.list_sections())))
    user_agent = "duoauthproxy/{0} ({1}; Python{2}; {3})".format(
        get_version(),
        platform.platform(),
        platform.python_version(),
        sections)
    http.set_user_agent(user_agent)

    # Authproxy uses globalLogPublisher to emit events. Defining a no-op emitter will squelch the creation
    # of the unwatned twistd default logging mechanisms.
    def no_op_emitter(eventDict):
        pass

    application.setComponent(ILogObserver, no_op_emitter)

    return application