예제 #1
0
def no_detail_on_success(request, response):
    """
    This policy function is used with the AUTHZ scope.
    If the boolean value no_detail_on_success is set,
    the details will be stripped if
    the authentication request was successful.

    :param request:
    :param response:
    :return:
    """
    content = response.json

    # get the serials from a policy definition
    detailPol = Match.action_only(g, scope=SCOPE.AUTHZ, action=ACTION.NODETAILSUCCESS)\
        .policies(write_to_audit_log=False)
    if detailPol and content.get("result", {}).get("value"):
        # The policy was set, we need to strip the details, if the
        # authentication was successful. (value=true)
        # None assures that we do not get an error, if "detail" does not exist.
        content.pop("detail", None)
        response.set_data(json.dumps(content))
        g.audit_object.add_policy([p.get("name") for p in detailPol])

    return response
예제 #2
0
    def api_endpoint(cls, request, g):
        """
        This provides a function to be plugged into the API endpoint
        /ttype/u2f

        The u2f token can return the facet list at this URL.

        :param request: The Flask request
        :param g: The Flask global object g
        :return: Flask Response or text
        """
        configured_app_id = get_from_config("u2f.appId")
        if configured_app_id is None:
            raise ParameterError("u2f is not configured")
        app_id = configured_app_id.strip("/")

        # Read the facets from the policies
        pol_facets = Match.action_only(
            g, scope=SCOPE.AUTH,
            action=U2FACTION.FACETS).action_values(unique=False)
        facet_list = ["https://{0!s}".format(x) for x in pol_facets]
        facet_list.append(app_id)

        log.debug("Sending facets lists for appId {0!s}: {1!s}".format(
            app_id, facet_list))
        res = {
            "trustedFacets": [{
                "version": {
                    "major": 1,
                    "minor": 0
                },
                "ids": facet_list
            }]
        }
        return "fido.trusted-apps+json", res
예제 #3
0
def check_serial(request, response):
    """
    This policy function is to be used in a decorator of an API function.
    It checks, if the token, that was used in the API call has a serial
    number that is allowed to be used.

    If not, a PolicyException is raised.

    :param response: The response of the decorated function
    :type response: Response object
    :return: A new (maybe modified) response
    """
    serial = response.json.get("detail", {}).get("serial")
    # get the serials from a policy definition
    allowed_serials = Match.action_only(g, scope=SCOPE.AUTHZ, action=ACTION.SERIAL).action_values(unique=False)

    # If we can compare a serial and if we do serial matching!
    if serial and allowed_serials:
        serial_matches = False
        for allowed_serial in allowed_serials:
            if re.search(allowed_serial, serial):
                serial_matches = True
                break
        if serial_matches is False:
            g.audit_object.log({"action_detail": "Serial is not allowed for "
                                                 "authentication!"})
            raise PolicyError("Serial is not allowed for authentication!")
    return response
예제 #4
0
def no_detail_on_fail(request, response):
    """
    This policy function is used with the AUTHZ scope.
    If the boolean value no_detail_on_fail is set,
    the details will be stripped if
    the authentication request failed.

    :param request:
    :param response:
    :return:
    """
    content = response.json

    # get the serials from a policy definition
    detailPol = Match.action_only(
        g, scope=SCOPE.AUTHZ,
        action=ACTION.NODETAILFAIL).policies(write_to_audit_log=False)
    if detailPol and content.get("result", {}).get("value") is False:
        # The policy was set, we need to strip the details, if the
        # authentication was successful. (value=true)
        del content["detail"]
        response.set_data(json.dumps(content))
        g.audit_object.add_policy([p.get("name") for p in detailPol])

    return response
예제 #5
0
def register_status():
    """
    This endpoint returns the information if registration is allowed or not.
    This is used by the UI to either display the registration button or not.

    :return: JSON with value=True or value=False
    """
    resolvername = Match.action_only(g, scope=SCOPE.REGISTER, action=ACTION.RESOLVER)\
        .action_values(unique=True)
    result = bool(resolvername)
    g.audit_object.log({"info": result, "success": True})
    return send_result(result)
예제 #6
0
def add_user_detail_to_response(request, response):
    """
    This policy decorated is used in the AUTHZ scope.
    If the boolean value add_user_in_response is set,
    the details will contain a dictionary "user" with all user details.

    :param request:
    :param response:
    :return:
    """
    content = response.json

    # Check for ADD USER IN RESPONSE
    detail_pol = Match.action_only(g, scope=SCOPE.AUTHZ, action=ACTION.ADDUSERINRESPONSE)\
        .policies(write_to_audit_log=False)
    if detail_pol and content.get("result", {}).get("value") and request.User:
        # The policy was set, we need to add the user
        #  details
        ui = request.User.info.copy()
        ui["password"] = ""
        for key, value in ui.items():
            if type(value) == datetime.datetime:
                ui[key] = str(value)
        content.setdefault("detail", {})["user"] = ui
        g.audit_object.add_policy([p.get("name") for p in detail_pol])

    # Check for ADD RESOLVER IN RESPONSE
    detail_pol = Match.action_only(g, scope=SCOPE.AUTHZ, action=ACTION.ADDRESOLVERINRESPONSE)\
        .policies(write_to_audit_log=False)
    if detail_pol and content.get("result", {}).get("value") and request.User:
        # The policy was set, we need to add the resolver and the realm
        content.setdefault("detail",
                           {})["user-resolver"] = request.User.resolver
        content["detail"]["user-realm"] = request.User.realm
        g.audit_object.add_policy([p.get("name") for p in detail_pol])

    response.set_data(json.dumps(content))
    return response
예제 #7
0
def check_tokeninfo(request, response):
    """
    This policy function is used as a decorator for the validate API.
    It checks after a successful authentication if the token has a matching
    tokeninfo field. If it does not match, authorization is denied. Then
    a PolicyException is raised.

    :param response: The response of the decorated function
    :type response: Response object
    :return: A new modified response
    """
    serial = response.json.get("detail", {}).get("serial")

    if serial:
        tokeninfos_pol = Match.action_only(g, scope=SCOPE.AUTHZ, action=ACTION.TOKENINFO)\
            .action_values(unique=False, allow_white_space_in_action=True)
        if tokeninfos_pol:
            tokens = get_tokens(serial=serial)
            if len(tokens) == 1:
                token_obj = tokens[0]
                for tokeninfo_pol in tokeninfos_pol:
                    try:
                        key, regex, _r = tokeninfo_pol.split("/")
                        value = token_obj.get_tokeninfo(key, "")
                        if re.search(regex, value):
                            log.debug(
                                u"Regular expression {0!s} "
                                u"matches the tokeninfo field {1!s}.".format(
                                    regex, key))
                        else:
                            log.info(
                                u"Tokeninfo field {0!s} with contents {1!s} "
                                u"does not match {2!s}".format(
                                    key, value, regex))
                            raise PolicyError(
                                "Tokeninfo field {0!s} with contents does not"
                                " match regular expression.".format(key))
                    except ValueError:
                        log.warning(u"invalid tokeinfo policy: {0!s}".format(
                            tokeninfo_pol))

    return response
예제 #8
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
예제 #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"], 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)
    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:
        if is_remote_user_allowed(request):
            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 = ""

    render_context = {
        'instance': instance,
        'backendUrl': backend_url,
        'browser_lang': browser_lang,
        'remote_user': 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,
        'external_links': external_links,
        'login_text': login_text,
        'logo': logo,
        'page_title': page_title
    }

    return send_html(render_template("index.html", **render_context))
예제 #10
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")
        realm = realm or get_default_realm()

        logout_time_pol = Match.realm(g,
                                      scope=SCOPE.WEBUI,
                                      action=ACTION.LOGOUTTIME,
                                      realm=realm).action_values(unique=True)
        timeout_action_pol = Match.realm(
            g, scope=SCOPE.WEBUI, action=ACTION.TIMEOUT_ACTION,
            realm=realm).action_values(unique=True)
        token_page_size_pol = Match.realm(
            g, scope=SCOPE.WEBUI, action=ACTION.TOKENPAGESIZE,
            realm=realm).action_values(unique=True)
        user_page_size_pol = Match.realm(
            g, scope=SCOPE.WEBUI, action=ACTION.USERPAGESIZE,
            realm=realm).action_values(unique=True)
        token_wizard_2nd = (role == ROLE.USER and Match.realm(
            g, scope=SCOPE.WEBUI, action=ACTION.TOKENWIZARD2ND,
            realm=realm).policies())
        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.realm(g,
                                       scope=SCOPE.WEBUI,
                                       action=ACTION.USERDETAILS,
                                       realm=realm).policies()
        search_on_enter = Match.realm(g,
                                      scope=SCOPE.WEBUI,
                                      action=ACTION.SEARCH_ON_ENTER,
                                      realm=realm).policies()
        hide_welcome = Match.realm(g,
                                   scope=SCOPE.WEBUI,
                                   action=ACTION.HIDE_WELCOME,
                                   realm=realm).any()
        hide_buttons = Match.realm(g,
                                   scope=SCOPE.WEBUI,
                                   action=ACTION.HIDE_BUTTONS,
                                   realm=realm).any()
        default_tokentype_pol = Match.realm(
            g, scope=SCOPE.WEBUI, action=ACTION.DEFAULT_TOKENTYPE,
            realm=realm).action_values(unique=True)
        show_seed = Match.realm(g,
                                scope=SCOPE.WEBUI,
                                action=ACTION.SHOW_SEED,
                                realm=realm).any()
        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]

        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"]["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"][
            "subscription_status"] = subscription_status()
        response.set_data(json.dumps(content))
    return response
예제 #11
0
def register_post():
    """
    Register a new user in the realm/userresolver. To do so, the user
    resolver must be writeable like an SQLResolver.

    Registering a user in fact creates a new user and also creates the first
    token for the user. The following values are needed to register the user:

    * username (mandatory)
    * givenname (mandatory)
    * surname (mandatory)
    * email address (mandatory)
    * password (mandatory)
    * mobile phone (optional)
    * telephone (optional)

    The user receives a registration token via email to be able to login with
    his self chosen password and the registration token.

    :jsonparam username: The login name of the new user. Check if it already
        exists
    :jsonparam givenname: The givenname of the new user
    :jsonparam surname: The surname of the new user
    :jsonparam email: The email address of the new user
    :jsonparam password: The password of the new user. This is the resolver
        password of the new user.
    :jsonparam mobile: The mobile phone number
    :jsonparam phone: The phone number (land line) of the new user

    :return: a json result with a boolean "result": true
    """
    username = getParam(request.all_data, "username", required)
    surname = getParam(request.all_data, "surname", required)
    givenname = getParam(request.all_data, "givenname", required)
    email = getParam(request.all_data, "email", required)
    password = getParam(request.all_data, "password", required)
    mobile = getParam(request.all_data, "mobile")
    phone = getParam(request.all_data, "phone")
    options = {"g": g, "clientip": g.client_ip}
    g.audit_object.log({"info": username})
    # Add all params to the options
    for key, value in request.all_data.items():
        if value and key not in ["g", "clientip"]:
            options[key] = value

    # 0. check, if we can do the registration at all!
    smtpconfig = Match.action_only(g, scope=SCOPE.REGISTER, action=ACTION.EMAILCONFIG)\
        .action_values(unique=True)
    if not smtpconfig:
        raise RegistrationError("No SMTP server configuration specified!")

    # 1. determine, in which resolver/realm the user should be created
    realm = Match.action_only(g, scope=SCOPE.REGISTER, action=ACTION.REALM)\
        .action_values(unique=True)
    if not realm:
        # No policy for realm, so we use the default realm
        realm = get_default_realm
    else:
        # we use the first realm in the list
        realm = list(realm)[0]
    resolvername = Match.action_only(g, scope=SCOPE.REGISTER, action=ACTION.RESOLVER)\
        .action_values(unique=True)
    if not resolvername:
        raise RegistrationError("No resolver specified to register in!")
    resolvername = list(resolvername)[0]
    # Check if the user exists
    user = User(username, realm=realm, resolver=resolvername)
    if user.exist():
        raise RegistrationError("The username is already registered!")
    # Create user
    uid = create_user(
        resolvername, {
            "username": username,
            "email": email,
            "phone": phone,
            "mobile": mobile,
            "surname": surname,
            "givenname": givenname,
            "password": password
        })

    # 3. create a registration token for this user
    user = User(username, realm=realm, resolver=resolvername)
    token = init_token({"type": "registration"}, user=user)
    # 4. send the registration token to the users email
    registration_key = token.init_details.get("otpkey")

    smtpconfig = list(smtpconfig)[0]
    # Send the registration key via email
    body = Match.action_only(g, scope=SCOPE.REGISTER, action=ACTION.REGISTERBODY)\
        .action_values(unique=True)
    body = body or DEFAULT_BODY
    email_sent = send_email_identifier(smtpconfig, email,
                                       "Your privacyIDEA registration",
                                       body.format(regkey=registration_key))
    if not email_sent:
        log.warning("Failed to send registration email to {0!r}".format(email))
        # delete registration token
        token.delete()
        # delete user
        user.delete()
        raise RegistrationError("Failed to send email!")

    log.debug("Registration email sent to {0!r}".format(email))

    g.audit_object.log({"success": email_sent})
    return send_result(email_sent)