def _get_local_config(config_filename=None, apply_overrides=True): """ Load local config file optionally specified by 'config_filename' Args: See get_config Returns: A ConfigProvider object """ try: if not config_filename: root = util.get_home_dir() config_filename = os.path.join(root, 'conf', 'authproxy.cfg') # open configfile and construct ConfigProvider with open(config_filename, "r") as config_file: configuration = ConfigProvider.from_ini_file( config_file, os.path.abspath(config_filename), apply_overrides) except IOError: raise ConfigError( 'Config file missing or unreadable: {0}'.format(config_filename)) return configuration
def __init__(self, args): win32serviceutil.ServiceFramework.__init__(self, args) self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) self.duo_root = util.get_home_dir()
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