def test_23_get_client_ip(self): class RequestMock(): blueprint = None remote_addr = None all_data = {} access_route = [] r = RequestMock() r.blueprint = "token_blueprint" # The real client direct_client = "10.0.0.1" r.remote_addr = direct_client # The client parameter client_parameter = "192.168.2.1" r.all_data = {"client": client_parameter} # The X-Forwarded-For client_proxy = "172.16.1.2" r.access_route = [client_proxy] proxy_settings = "" ip = get_client_ip(r, proxy_settings) self.assertEqual(ip, direct_client) # If there is a proxy_setting, the X-Forwarded-For will # work, but not the client_parameter proxy_settings = direct_client ip = get_client_ip(r, proxy_settings) self.assertEqual(ip, client_proxy) # If the request is a validate request, the # client_parameter will overrule the X-Forwarded-For r.blueprint = "validate_blueprint" ip = get_client_ip(r, proxy_settings) self.assertEqual(ip, client_parameter)
def before_request(): """ This is executed before the request """ ensure_no_config_object() request.all_data = get_all_params(request.values, request.data) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config) g.event_config = EventConfiguration() # access_route contains the ip adresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) g.audit_object.log({ "success": False, "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "action_detail": "", "info": "" })
def before_request(): """ This is executed before the request """ ensure_no_config_object() request.all_data = get_all_params(request) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host # Create a policy_object, that reads the database audit settings # and contains the complete policy definition during the request. # This audit_object can be used in the postpolicy and prepolicy and it # can be passed to the innerpolicies. g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config) # access_route contains the ip adresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) g.serial = getParam(request.all_data, "serial") or None g.audit_object.log({ "success": False, "action_detail": "", "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "info": "" })
def is_remote_user_allowed(req): """ Checks if the REMOTE_USER server variable is allowed to be used. .. note:: This is not used as a decorator! :param req: The flask request, containing the remote user and the client IP :return: """ res = False if req.remote_user: loginname, realm = split_user(req.remote_user) realm = realm or get_default_realm() # Check if the remote user is allowed if "client_ip" not in g: g.client_ip = get_client_ip( req, get_from_config(SYSCONF.OVERRIDECLIENT)) if "policy_object" not in g: g.policy_object = PolicyClass() ruser_active = g.policy_object.get_action_values(ACTION.REMOTE_USER, scope=SCOPE.WEBUI, user=loginname, realm=realm, client=g.client_ip) res = ruser_active return res
def is_remote_user_allowed(req): """ Checks if the REMOTE_USER server variable is allowed to be used. .. note:: This is not used as a decorator! :param req: The flask request, containing the remote user and the client IP :return: """ res = False if req.remote_user: loginname, realm = split_user(req.remote_user) realm = realm or get_default_realm() # Check if the remote user is allowed if "client_ip" not in g: g.client_ip = get_client_ip(req, get_from_config(SYSCONF.OVERRIDECLIENT)) if "policy_object" not in g: g.policy_object = PolicyClass() ruser_active = g.policy_object.get_action_values(ACTION.REMOTE_USER, scope=SCOPE.WEBUI, user=loginname, realm=realm, client=g.client_ip) res = ruser_active return res
def before_request(): """ This is executed before the request. user_required checks if there is a logged in admin or user The checks for ONLY admin are preformed in api/system.py """ # remove session from param and gather all parameters, either # from the Form data or from JSON in the request body. request.all_data = get_all_params(request.values, request.data) g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config) g.event_config = EventConfiguration() # access_route contains the ip adresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host # Already get some typical parameters to log serial = getParam(request.all_data, "serial") realm = getParam(request.all_data, "realm") user_loginname = "" if "token_blueprint" in request.endpoint: # In case of token endpoint we evaluate the user in the request. # Note: In policy-endpoint "user" is part of the policy configuration # and will cause an exception user = get_user_from_param(request.all_data) user_loginname = user.login realm = user.realm or realm g.audit_object.log({"success": False, "serial": serial, "user": user_loginname, "realm": realm, "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "action_detail": "", "info": ""}) if g.logged_in_user.get("role") == "user": # A user is calling this API # In case the token API is called by the user and not by the admin we # need to restrict the token view. CurrentUser = get_user_from_param({"user": g.logged_in_user.get( "username"), "realm": g.logged_in_user.get( "realm")}) request.all_data["user"] = CurrentUser.login request.all_data["resolver"] = CurrentUser.resolver request.all_data["realm"] = CurrentUser.realm g.audit_object.log({"user": CurrentUser.login, "realm": CurrentUser.realm}) else: # An administrator is calling this API g.audit_object.log({"administrator": g.logged_in_user.get("username")})
def before_request(): """ This is executed before the request """ ensure_no_config_object() request.all_data = get_all_params(request.values, request.data) # get additional request information such as parameters in the # call path from the view_args request.all_data.update(request.view_args) request.User = get_user_from_param(request.all_data) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host # Create a policy_object, that reads the database audit settings # and contains the complete policy definition during the request. # This audit_object can be used in the postpolicy and prepolicy and it # can be passed to the innerpolicies. g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config, g.startdate) g.event_config = EventConfiguration() # access_route contains the ip addresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) # Save the HTTP header in the localproxy object g.request_headers = request.headers g.serial = getParam(request.all_data, "serial", default=None) g.audit_object.log({"success": False, "action_detail": "", "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "info": ""})
def before_request(): """ This is executed before the request """ update_config_object() request.all_data = get_all_params(request.values, request.data) request.User = get_user_from_param(request.all_data) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host # Create a policy_object, that reads the database audit settings # and contains the complete policy definition during the request. # This audit_object can be used in the postpolicy and prepolicy and it # can be passed to the innerpolicies. g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config) g.event_config = EventConfiguration() # access_route contains the ip addresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) g.audit_object.log({"success": False, "action_detail": "", "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "info": ""})
def before_request(): """ This is executed before the request """ ensure_no_config_object() request.all_data = get_all_params(request.values, request.data) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config) g.event_config = EventConfiguration() # access_route contains the ip adresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) g.audit_object.log({"success": False, "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "action_detail": "", "info": ""}) username = getParam(request.all_data, "username") if username: # We only fill request.User, if we really have a username. # On endpoints like /auth/rights, this is not available loginname, realm = split_user(username) # overwrite the split realm if we have a realm parameter. Default back to default_realm realm = getParam(request.all_data, "realm", default=realm) or realm or get_default_realm() # Prefill the request.User. This is used by some pre-event handlers request.User = User(loginname, realm)
def before_request(): """ This is executed before the request """ g.policy_object = PolicyClass() g.audit_object = None # access_route contains the ip addresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT))
def test_23_get_client_ip(self): class RequestMock(): blueprint = None remote_addr = None all_data = {} access_route = [] r = RequestMock() r.blueprint = "token_blueprint" # The real client direct_client = "10.0.0.1" r.remote_addr = direct_client # The client parameter client_parameter = "192.168.2.1" r.all_data = {"client": client_parameter} # The X-Forwarded-For client_proxy = "172.16.1.2" r.access_route = [client_proxy] # Setup: # 192.168.2.1 ---------> 172.16.1.2 -------> 10.0.0.1 --------> privacyIDEA # client_parameter client_proxy direct_client ip = get_client_ip(r, "") self.assertEqual(ip, direct_client) # If there is a proxy_setting, the X-Forwarded-For will # work, but not the client_parameter ip = get_client_ip(r, "10.0.0.1") self.assertEqual(ip, client_proxy) # If the request is a validate request: r.blueprint = "validate_blueprint" # ... the direct client may map anywhere, but as we also have a X-Forwarded-For header, # the header takes precedence! ip = get_client_ip(r, "10.0.0.1") self.assertEqual(ip, client_proxy) # ... if we now also allow the client_proxy to rewrite IPs, the client parameter is respected ip = get_client_ip(r, "10.0.0.1>172.16.1.2>0.0.0.0/0") self.assertEqual(ip, client_parameter) # ... even if we have multiple proxy settings ip = get_client_ip( r, "10.0.0.1>198.168.1.3, 10.0.0.1>172.16.1.2>1.2.3.4, 10.0.0.1>172.16.1.2>0.0.0.0/0" ) self.assertEqual(ip, client_parameter) # Check situation if there is no X-Forwarded-For header, but a client parameter: r.access_route = [direct_client] ip = get_client_ip(r, "10.0.0.1") self.assertEqual(ip, client_parameter) # The client parameter is not respected for the token endpoints r.blueprint = "token_blueprint" ip = get_client_ip(r, "10.0.0.1") self.assertEqual(ip, direct_client)
def before_request(): """ This is executed before the request """ request.all_data = get_all_params(request.values, request.data) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config) # access_route contains the ip adresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) g.audit_object.log({"success": False, "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "action_detail": "", "info": ""})
def before_request(): """ This is executed before the request. user_required checks if there is a logged in admin or user The checks for ONLY admin are preformed in api/system.py """ # remove session from param and gather all parameters, either # from the Form data or from JSON in the request body. request.all_data = get_all_params(request.values, request.data) g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config) g.event_config = EventConfiguration() # access_route contains the ip adresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host # Already get some typical parameters to log serial = getParam(request.all_data, "serial") realm = getParam(request.all_data, "realm") user_loginname = "" if "token_blueprint" in request.endpoint: # In case of token endpoint we evaluate the user in the request. # Note: In policy-endpoint "user" is part of the policy configuration # and will cause an exception user = get_user_from_param(request.all_data) user_loginname = user.login realm = user.realm or realm g.audit_object.log({ "success": False, "serial": serial, "user": user_loginname, "realm": realm, "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "action_detail": "", "info": "" }) if g.logged_in_user.get("role") == "user": # A user is calling this API # In case the token API is called by the user and not by the admin we # need to restrict the token view. CurrentUser = get_user_from_param({ "user": g.logged_in_user.get("username"), "realm": g.logged_in_user.get("realm") }) request.all_data["user"] = CurrentUser.login request.all_data["resolver"] = CurrentUser.resolver request.all_data["realm"] = CurrentUser.realm g.audit_object.log({ "user": CurrentUser.login, "realm": CurrentUser.realm }) else: # An administrator is calling this API g.audit_object.log({"administrator": g.logged_in_user.get("username")})
def single_page_application(): instance = request.script_root if instance == "/": instance = "" # The backend URL should come from the configuration of the system. backend_url = "" if current_app.config.get("PI_UI_DEACTIVATED"): # Do not provide the UI return render_template("deactivated.html") # The default theme. We can change this later theme = current_app.config.get("PI_CSS", DEFAULT_THEME) # Get further customizations customization = current_app.config.get("PI_CUSTOMIZATION", "/static/customize/") customization = customization.strip('/') # TODO: we should add the CSS into PI_CUSTOMZATION/css # Enrollment-Wizard: # PI_CUSTOMIZATION/views/includes/token.enroll.pre.top.html # PI_CUSTOMIZATION/views/includes/token.enroll.pre.bottom.html # PI_CUSTOMIZATION/views/includes/token.enroll.post.top.html # PI_CUSTOMIZATION/views/includes/token.enroll.post.bottom.html # Get the hidden external links external_links = current_app.config.get("PI_EXTERNAL_LINKS", True) # Get the logo file logo = current_app.config.get("PI_LOGO", "privacyIDEA1.png") browser_lang = request.accept_languages.best_match(["en", "de", "de-DE"], default="en").split("-")[0] # The page title can be configured in pi.cfg page_title = current_app.config.get("PI_PAGE_TITLE", "privacyIDEA Authentication System") # check if login with REMOTE_USER is allowed. remote_user = "" password_reset = False if not hasattr(request, "all_data"): request.all_data = {} # Depending on displaying the realm dropdown, we fill realms or not. policy_object = PolicyClass() realms = "" client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) realm_dropdown = policy_object.get_policies(action=ACTION.REALMDROPDOWN, scope=SCOPE.WEBUI, client=client_ip, active=True) if realm_dropdown: try: realm_dropdown_values = policy_object.get_action_values( action=ACTION.REALMDROPDOWN, scope=SCOPE.WEBUI, client=client_ip) # Use the realms from the policy. realms = ",".join(realm_dropdown_values) except AttributeError as ex: # The policy is still a boolean realm_dropdown action # Thus we display ALL realms realms = ",".join(get_realms()) try: if is_remote_user_allowed(request): remote_user = request.remote_user password_reset = is_password_reset() hsm_ready = True except HSMException: hsm_ready = False # Use policies to determine the customization of menu # and baseline. get_action_values returns an array! sub_state = subscription_status() customization_menu_file = policy_object.get_action_values( allow_white_space_in_action=True, action=ACTION.CUSTOM_MENU, scope=SCOPE.WEBUI, client=client_ip, unique=True) if len(customization_menu_file) and list(customization_menu_file)[0] \ and sub_state not in [1, 2]: customization_menu_file = list(customization_menu_file)[0] else: customization_menu_file = "templates/menu.html" customization_baseline_file = policy_object.get_action_values( allow_white_space_in_action=True, action=ACTION.CUSTOM_BASELINE, scope=SCOPE.WEBUI, client=client_ip, unique=True) if len(customization_baseline_file) and list(customization_baseline_file)[0] \ and sub_state not in [1, 2]: customization_baseline_file = list(customization_baseline_file)[0] else: customization_baseline_file = "templates/baseline.html" login_text = policy_object.get_action_values( allow_white_space_in_action=True, action=ACTION.LOGIN_TEXT, scope=SCOPE.WEBUI, client=client_ip, unique=True ) if len(login_text) and list(login_text)[0] and sub_state not in [1, 2]: login_text = list(login_text)[0] else: login_text = "" return render_template("index.html", instance=instance, backendUrl=backend_url, browser_lang=browser_lang, remote_user=remote_user, theme=theme, password_reset=password_reset, hsm_ready=hsm_ready, has_job_queue=str(has_job_queue()), customization=customization, customization_menu_file=customization_menu_file, customization_baseline_file=customization_baseline_file, realms=realms, external_links=external_links, login_text=login_text, logo=logo, page_title=page_title)
def before_request(): """ This is executed before the request. user_required checks if there is a logged in admin or user The checks for ONLY admin are preformed in api/system.py """ # remove session from param and gather all parameters, either # from the Form data or from JSON in the request body. ensure_no_config_object() request.all_data = get_all_params(request.values, request.data) if g.logged_in_user.get("role") == "user": # A user is calling this API. First thing we do is restricting the user parameter. # ...to restrict token view, audit view or token actions. request.all_data["user"] = g.logged_in_user.get("username") request.all_data["realm"] = g.logged_in_user.get("realm") try: request.User = get_user_from_param(request.all_data) # overwrite or set the resolver parameter in case of a logged in user if g.logged_in_user.get("role") == "user": request.all_data["resolver"] = request.User.resolver except AttributeError: # Some endpoints do not need users OR e.g. the setPolicy endpoint # takes a list as the userobject request.User = None except UserError: # In cases like the policy API, the parameter "user" is part of the # policy and will not resolve to a user object request.User = User() g.policy_object = PolicyClass() g.audit_object = getAudit(current_app.config) g.event_config = EventConfiguration() # access_route contains the ip adresses of all clients, hops and proxies. g.client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) privacyidea_server = current_app.config.get("PI_AUDIT_SERVERNAME") or \ request.host # Already get some typical parameters to log serial = getParam(request.all_data, "serial") if serial: tokentype = get_token_type(serial) else: tokentype = None if request.User: audit_username = request.User.login audit_realm = request.User.realm audit_resolver = request.User.resolver else: audit_realm = getParam(request.all_data, "realm") audit_resolver = getParam(request.all_data, "resolver") audit_username = getParam(request.all_data, "user") g.audit_object.log({ "success": False, "serial": serial, "user": audit_username, "realm": audit_realm, "resolver": audit_resolver, "token_type": tokentype, "client": g.client_ip, "client_user_agent": request.user_agent.browser, "privacyidea_server": privacyidea_server, "action": "{0!s} {1!s}".format(request.method, request.url_rule), "action_detail": "", "info": "" }) if g.logged_in_user.get("role") == "admin": # An administrator is calling this API g.audit_object.log({"administrator": g.logged_in_user.get("username")})
def single_page_application(): instance = request.script_root if instance == "/": instance = "" # The backend URL should come from the configuration of the system. backend_url = "" if current_app.config.get("PI_UI_DEACTIVATED"): # Do not provide the UI return render_template("deactivated.html") # The default theme. We can change this later theme = current_app.config.get("PI_CSS", DEFAULT_THEME) # Get further customizations customization = current_app.config.get("PI_CUSTOMIZATION", "/static/customize/") customization = customization.strip('/') # TODO: we should add the CSS into PI_CUSTOMZATION/css # Enrollment-Wizard: # PI_CUSTOMIZATION/views/includes/token.enroll.pre.top.html # PI_CUSTOMIZATION/views/includes/token.enroll.pre.bottom.html # PI_CUSTOMIZATION/views/includes/token.enroll.post.top.html # PI_CUSTOMIZATION/views/includes/token.enroll.post.bottom.html # Get the hidden external links external_links = current_app.config.get("PI_EXTERNAL_LINKS", True) # Get the logo file logo = current_app.config.get("PI_LOGO", "privacyIDEA1.png") browser_lang = request.accept_languages.best_match( ["en", "de", "de-DE"], default="en").split("-")[0] # The page title can be configured in pi.cfg page_title = current_app.config.get("PI_PAGE_TITLE", "privacyIDEA Authentication System") # check if login with REMOTE_USER is allowed. remote_user = "" password_reset = False if not hasattr(request, "all_data"): request.all_data = {} # Depending on displaying the realm dropdown, we fill realms or not. policy_object = PolicyClass() realms = "" client_ip = get_client_ip(request, get_from_config(SYSCONF.OVERRIDECLIENT)) realm_dropdown = policy_object.get_policies(action=ACTION.REALMDROPDOWN, scope=SCOPE.WEBUI, client=client_ip, active=True) if realm_dropdown: try: realm_dropdown_values = policy_object.get_action_values( action=ACTION.REALMDROPDOWN, scope=SCOPE.WEBUI, client=client_ip) # Use the realms from the policy. realms = ",".join(realm_dropdown_values) except AttributeError as ex: # The policy is still a boolean realm_dropdown action # Thus we display ALL realms realms = ",".join(get_realms()) try: if is_remote_user_allowed(request): remote_user = request.remote_user password_reset = is_password_reset() hsm_ready = True except HSMException: hsm_ready = False # Use policies to determine the customization of menu # and baseline. get_action_values returns an array! sub_state = subscription_status() customization_menu_file = policy_object.get_action_values( allow_white_space_in_action=True, action=ACTION.CUSTOM_MENU, scope=SCOPE.WEBUI, client=client_ip, unique=True) if len(customization_menu_file) and list(customization_menu_file)[0] \ and sub_state not in [1, 2]: customization_menu_file = list(customization_menu_file)[0] else: customization_menu_file = "templates/menu.html" customization_baseline_file = policy_object.get_action_values( allow_white_space_in_action=True, action=ACTION.CUSTOM_BASELINE, scope=SCOPE.WEBUI, client=client_ip, unique=True) if len(customization_baseline_file) and list(customization_baseline_file)[0] \ and sub_state not in [1, 2]: customization_baseline_file = list(customization_baseline_file)[0] else: customization_baseline_file = "templates/baseline.html" login_text = policy_object.get_action_values( allow_white_space_in_action=True, action=ACTION.LOGIN_TEXT, scope=SCOPE.WEBUI, client=client_ip, unique=True) if len(login_text) and list(login_text)[0] and sub_state not in [1, 2]: login_text = list(login_text)[0] else: login_text = "" return render_template( "index.html", instance=instance, backendUrl=backend_url, browser_lang=browser_lang, remote_user=remote_user, theme=theme, password_reset=password_reset, hsm_ready=hsm_ready, has_job_queue=str(has_job_queue()), customization=customization, customization_menu_file=customization_menu_file, customization_baseline_file=customization_baseline_file, realms=realms, external_links=external_links, login_text=login_text, logo=logo, page_title=page_title)