예제 #1
0
def upgrade():
    node = get_privacyidea_node()
    try:
        # The ``node`` field is not nullable. Hence, We set the server_default to the current node to ensure that
        # the ``node`` of all existing rows is set to the current node.
        op.add_column('clientapplication', sa.Column('node', sa.Unicode(length=255),
                                                     nullable=False, server_default=node))
        op.drop_constraint(u'caix', 'clientapplication', type_='unique')
        op.create_unique_constraint('caix', 'clientapplication', ['ip', 'clienttype', 'node'])
    except Exception as exx:
        print("Failed to add 'node' column to 'clientapplication' table")
        print(exx)
예제 #2
0
def reset(counter_name):
    """
    Reset the counter value in the database to 0.
    If the counter does not exist yet, create the counter.
    :param counter_name: The name/identifier of the counter
    :return:
    """
    node = get_privacyidea_node()
    counters = EventCounter.query.filter_by(counter_name=counter_name).count()
    if not counters:
        counter = EventCounter(counter_name, 0, node=node)
        counter.save()
    else:
        _reset_counter_on_all_nodes(counter_name)
예제 #3
0
def increase(counter_name):
    """
    Increase the counter value in the database.
    If the counter does not exist yet, create the counter.

    :param counter_name: The name/identifier of the counter
    :return: None
    """
    # If there is no table row for the current node, create one.
    node = get_privacyidea_node()
    counter = EventCounter.query.filter_by(counter_name=counter_name,
                                           node=node).first()
    if not counter:
        counter = EventCounter(counter_name, 0, node=node)
        counter.save()
    counter.increase()
예제 #4
0
def save_clientapplication(ip, clienttype):
    """
    Save (or update) the IP and the clienttype to the database table.

    :param ip: The IP address of the requesting client.
    :type ip: well formatted string or IPAddress
    :param clienttype: The type of the client
    :type ip: basestring
    :return: None
    """
    node = get_privacyidea_node()
    # Check for a valid IP address
    ip = IPAddress(ip)
    # TODO: resolve hostname
    app = ClientApplication(ip="{0!s}".format(ip),
                            clienttype=clienttype,
                            node=node)
    app.save()
예제 #5
0
def upgrade():

    try:
        # Step 1: Create sequence on Postgres
        seq = sa.Sequence('eventcounter_seq')
        try:
            create_seq(seq)
        except Exception as _e:
            pass
        # Step 2: Create new eventcounter_new table
        op.create_table('eventcounter_new',
                        sa.Column("id",
                                  sa.Integer,
                                  sa.Sequence("eventcounter_seq"),
                                  primary_key=True),
                        sa.Column("counter_name",
                                  sa.Unicode(80),
                                  nullable=False),
                        sa.Column("counter_value", sa.Integer, default=0),
                        sa.Column("node", sa.Unicode(255), nullable=False),
                        sa.UniqueConstraint('counter_name',
                                            'node',
                                            name='evctr_1'),
                        mysql_row_format='DYNAMIC')
        # Step 3: Migrate data from eventcounter to eventcounter_new
        node = get_privacyidea_node()
        bind = op.get_bind()
        session = orm.Session(bind=bind)
        for old_ctr in session.query(OldEventCounter).all():
            new_ctr = NewEventCounter(counter_name=old_ctr.counter_name,
                                      counter_value=old_ctr.counter_value,
                                      node=node)
            session.add(new_ctr)
            print("Migrating counter {!r}={} on node={!r} ...".format(
                new_ctr.counter_name, new_ctr.counter_value, node))
        session.commit()
        # Step 4: Remove eventcounter
        op.drop_table("eventcounter")
        op.rename_table("eventcounter_new", "eventcounter")
    except Exception as exx:
        session.rollback()
        print("Could not migrate table 'eventcounter'")
        print(exx)
예제 #6
0
def decrease(counter_name, allow_negative=False):
    """
    Decrease the counter value in the database.
    If the counter does not exist yet, create the counter.
    Also checks whether the counter is allowed to become negative.

    :param counter_name: The name/identifier of the counter
    :param allow_negative: Whether the counter can become negative. Note that even if this flag is not set,
                           the counter may become negative due to concurrent queries.
    :return: None
    """
    node = get_privacyidea_node()
    counter = EventCounter.query.filter_by(counter_name=counter_name,
                                           node=node).first()
    if not counter:
        counter = EventCounter(counter_name, 0, node=node)
        counter.save()
    # We are allowed to decrease the current counter object only if the overall
    # counter value is positive (because individual rows may be negative then),
    # or if we allow negative values. Otherwise, we need to reset all rows of all nodes.
    if read(counter_name) > 0 or allow_negative:
        counter.decrease()
    else:
        _reset_counter_on_all_nodes(counter_name)
예제 #7
0
def get_webui_settings(request, response):
    """
    This decorator is used in the /auth API to add configuration information
    like the logout_time or the policy_template_url to the response.
    :param request: flask request object
    :param response: flask response object
    :return: the response
    """
    content = response.json
    # check, if the authentication was successful, then we need to do nothing
    if content.get("result").get("status") is True:
        role = content.get("result").get("value").get("role")
        loginname = content.get("result").get("value").get("username")
        realm = content.get("result").get("value").get("realm") or get_default_realm()

        # At this point the logged in user is not necessarily a user object. It can
        # also be a local admin.
        logout_time_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.LOGOUTTIME,
                                        user=loginname, realm=realm).action_values(unique=True)
        timeout_action_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.TIMEOUT_ACTION,
                                           user=loginname, realm=realm).action_values(unique=True)
        token_page_size_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.TOKENPAGESIZE,
                                            user=loginname, realm=realm).action_values(unique=True)
        user_page_size_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.USERPAGESIZE,
                                           user=loginname, realm=realm).action_values(unique=True)
        token_wizard_2nd = bool(role == ROLE.USER
                                and Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.TOKENWIZARD2ND,
                                                  user=loginname, realm=realm).policies())
        admin_dashboard = (role == ROLE.ADMIN
                           and Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.ADMIN_DASHBOARD,
                                         user=loginname, realm=realm).any())
        token_wizard = False
        dialog_no_token = False
        if role == ROLE.USER:
            user_obj = User(loginname, realm)
            user_token_num = get_tokens(user=user_obj, count=True)
            token_wizard_pol = Match.user(g, scope=SCOPE.WEBUI, action=ACTION.TOKENWIZARD, user_object=user_obj).any()
            # We also need to check, if the user has not tokens assigned.
            # If the user has no tokens, we run the wizard. If the user
            # already has tokens, we do not run the wizard.
            token_wizard = token_wizard_pol and (user_token_num == 0)

            dialog_no_token_pol = Match.user(g, scope=SCOPE.WEBUI, action=ACTION.DIALOG_NO_TOKEN,
                                             user_object=user_obj).any()
            dialog_no_token = dialog_no_token_pol and (user_token_num == 0)
        user_details_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.USERDETAILS,
                                         user=loginname, realm=realm).policies()
        search_on_enter = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SEARCH_ON_ENTER,
                                        user=loginname, realm=realm).policies()
        hide_welcome = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.HIDE_WELCOME,
                                     user=loginname, realm=realm).any()
        hide_buttons = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.HIDE_BUTTONS,
                                     user=loginname, realm=realm).any()
        default_tokentype_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.DEFAULT_TOKENTYPE,
                                              user=loginname, realm=realm).action_values(unique=True)
        show_seed = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_SEED,
                                  user=loginname, realm=realm).any()
        show_node = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_NODE, realm=realm).any()
        qr_ios_authenticator = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_IOS_AUTHENTICATOR,
                                             user=loginname, realm=realm).any()
        qr_android_authenticator = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_ANDROID_AUTHENTICATOR,
                                                 user=loginname, realm=realm).any()
        qr_custom_authenticator_url = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_CUSTOM_AUTHENTICATOR,
                                                    user=loginname, realm=realm).action_values(unique=True)

        qr_image_android = create_img(DEFAULT_ANDROID_APP_URL) if qr_android_authenticator else None
        qr_image_ios = create_img(DEFAULT_IOS_APP_URL) if qr_ios_authenticator else None
        qr_image_custom = create_img(list(qr_custom_authenticator_url)[0]) if qr_custom_authenticator_url else None
        token_page_size = DEFAULT_PAGE_SIZE
        user_page_size = DEFAULT_PAGE_SIZE
        default_tokentype = DEFAULT_TOKENTYPE
        if len(token_page_size_pol) == 1:
            token_page_size = int(list(token_page_size_pol)[0])
        if len(user_page_size_pol) == 1:
            user_page_size = int(list(user_page_size_pol)[0])
        if len(default_tokentype_pol) == 1:
            default_tokentype = list(default_tokentype_pol)[0]

        logout_time = DEFAULT_LOGOUT_TIME
        if len(logout_time_pol) == 1:
            logout_time = int(list(logout_time_pol)[0])

        timeout_action = DEFAULT_TIMEOUT_ACTION
        if len(timeout_action_pol) == 1:
            timeout_action = list(timeout_action_pol)[0]

        policy_template_url_pol = Match.action_only(g, scope=SCOPE.WEBUI,
                                                    action=ACTION.POLICYTEMPLATEURL).action_values(unique=True)
        policy_template_url = DEFAULT_POLICY_TEMPLATE_URL
        if len(policy_template_url_pol) == 1:
            policy_template_url = list(policy_template_url_pol)[0]

        indexed_preset_attribute = Match.realm(g, scope=SCOPE.WEBUI, action="indexedsecret_preset_attribute",
                                               realm=realm).action_values(unique=True)
        if len(indexed_preset_attribute) == 1:
            content["result"]["value"]["indexedsecret_preset_attribute"] = list(indexed_preset_attribute)[0]

        # This only works for users, because the value of the policy does not change while logged in.
        if role == ROLE.USER and \
                Match.user(g, SCOPE.USER, "indexedsecret_force_attribute", user_obj).action_values(unique=False):
            content["result"]["value"]["indexedsecret_force_attribute"] = 1

        content["result"]["value"]["logout_time"] = logout_time
        content["result"]["value"]["token_page_size"] = token_page_size
        content["result"]["value"]["user_page_size"] = user_page_size
        content["result"]["value"]["policy_template_url"] = policy_template_url
        content["result"]["value"]["default_tokentype"] = default_tokentype
        content["result"]["value"]["user_details"] = len(user_details_pol) > 0
        content["result"]["value"]["token_wizard"] = token_wizard
        content["result"]["value"]["token_wizard_2nd"] = token_wizard_2nd
        content["result"]["value"]["admin_dashboard"] = admin_dashboard
        content["result"]["value"]["dialog_no_token"] = dialog_no_token
        content["result"]["value"]["search_on_enter"] = len(search_on_enter) > 0
        content["result"]["value"]["timeout_action"] = timeout_action
        content["result"]["value"]["hide_welcome"] = hide_welcome
        content["result"]["value"]["hide_buttons"] = hide_buttons
        content["result"]["value"]["show_seed"] = show_seed
        content["result"]["value"]["show_node"] = get_privacyidea_node() if show_node else ""
        content["result"]["value"]["subscription_status"] = subscription_status()
        content["result"]["value"]["qr_image_android"] = qr_image_android
        content["result"]["value"]["qr_image_ios"] = qr_image_ios
        content["result"]["value"]["qr_image_custom"] = qr_image_custom
        response.set_data(json.dumps(content))
    return response
예제 #8
0
 def test_07_node_names(self):
     node = get_privacyidea_node()
     self.assertEqual(node, "Node1")
     nodes = get_privacyidea_nodes()
     self.assertTrue("Node1" in nodes)
     self.assertTrue("Node2" in nodes)
예제 #9
0
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 send_html(render_template("deactivated.html"))

    # The default theme. We can change this later
    theme = current_app.config.get("PI_CSS", DEFAULT_THEME)
    theme = theme.strip('/')
    # Get further customizations
    customization = current_app.config.get("PI_CUSTOMIZATION",
                                           "/static/customize/")
    customization = customization.strip('/')
    custom_css = customization + "/css/custom.css" if current_app.config.get("PI_CUSTOM_CSS") else ""
    # 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)
    # Read the UI translation warning
    translation_warning = current_app.config.get("PI_TRANSLATION_WARNING", False)
    # Get the logo file
    logo = current_app.config.get("PI_LOGO", "privacyIDEA1.png")
    browser_lang = request.accept_languages.best_match(["en", "de", "de-DE", "nl", "fr", "it", "es"], 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.
    realms = ""
    realm_dropdown = Match.action_only(g, scope=SCOPE.WEBUI, action=ACTION.REALMDROPDOWN)\
        .policies(write_to_audit_log=False)
    show_node = get_privacyidea_node() \
        if Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_NODE).any(write_to_audit_log=False) else ""
    if realm_dropdown:
        try:
            realm_dropdown_values = Match.action_only(g, scope=SCOPE.WEBUI, action=ACTION.REALMDROPDOWN) \
                .action_values(unique=False, write_to_audit_log=False)
            # Use the realms from the policy.
            realms = ",".join(realm_dropdown_values)
        except AttributeError as _e:
            # The policy is still a boolean realm_dropdown action
            # Thus we display ALL realms
            realms = ",".join(get_realms())

    try:
        r = is_remote_user_allowed(request, write_to_audit_log=False)
        force_remote_user = r == REMOTE_USER.FORCE
        if r != REMOTE_USER.DISABLE:
            remote_user = request.remote_user
        password_reset = is_password_reset(g)
        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 = Match.action_only(g, action=ACTION.CUSTOM_MENU,
                                                scope=SCOPE.WEBUI)\
        .action_values(unique=True, allow_white_space_in_action=True, write_to_audit_log=False)
    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 = Match.action_only(g, action=ACTION.CUSTOM_BASELINE,
                                                    scope=SCOPE.WEBUI) \
        .action_values(unique=True, allow_white_space_in_action=True, write_to_audit_log=False)
    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 = Match.action_only(g, action=ACTION.LOGIN_TEXT, scope=SCOPE.WEBUI) \
        .action_values(unique=True, allow_white_space_in_action=True, write_to_audit_log=False)
    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 = ""

    gdpr_link = Match.action_only(g, action=ACTION.GDPR_LINK, scope=SCOPE.WEBUI) \
        .action_values(unique=True, allow_white_space_in_action=True, write_to_audit_log=False)
    if len(gdpr_link) and list(gdpr_link)[0] and sub_state not in [1, 2]:
        gdpr_link = list(gdpr_link)[0]
    else:
        gdpr_link = ""

    render_context = {
        'instance': instance,
        'backendUrl': backend_url,
        'browser_lang': browser_lang,
        'remote_user': remote_user,
        'force_remote_user': force_remote_user,
        'theme': theme,
        'translation_warning': translation_warning,
        'password_reset': password_reset,
        'hsm_ready': hsm_ready,
        'has_job_queue': str(has_job_queue()),
        'customization': customization,
        'custom_css': custom_css,
        'customization_menu_file': customization_menu_file,
        'customization_baseline_file': customization_baseline_file,
        'realms': realms,
        'show_node': show_node,
        'external_links': external_links,
        'login_text': login_text,
        'gdpr_link': gdpr_link,
        'logo': logo,
        'page_title': page_title
    }

    index_page = current_app.config.get("PI_INDEX_HTML") or "index.html"
    return send_html(render_template(index_page, **render_context))
예제 #10
0
 def test_07_node_names(self):
     node = get_privacyidea_node()
     self.assertEqual(node, "Node1")
     nodes = get_privacyidea_nodes()
     self.assertTrue("Node1" in nodes)
     self.assertTrue("Node2" in nodes)