Esempio n. 1
0
    def get_mobile_number(self, user=None):
        '''
        get the mobile number
            - from the token info or
            - if the policy allowes it, from the user info
        '''

        if not user:
            return self.get_phone()

        pol = get_client_policy(context['Client'],
                                scope="authentication",
                                user=user,
                                action="voice_dynamic_mobile_number")

        if not pol:
            return self.get_phone()

        get_dynamic = get_action_value(pol,
                                       scope='authentication',
                                       action="voice_dynamic_mobile_number",
                                       default=False)

        if not get_dynamic:
            return self.get_phone()

        user_detail = getUserDetail(user)
        return user_detail.get('mobile', self.get_phone())
Esempio n. 2
0
    def get_mobile_number(self, user=None):
        """
        get the mobile number
            - from the token info or
            - if the policy allowes it, from the user info
        """

        if not user:
            return self._getPhone()

        pol = get_client_policy(
            context["Client"],
            scope="authentication",
            user=user,
            action="sms_dynamic_mobile_number",
        )

        get_dynamic = get_action_value(
            pol,
            scope="authentication",
            action="sms_dynamic_mobile_number",
            default=False,
        )

        if not get_dynamic:
            return self._getPhone()

        user_detail = getUserDetail(user)
        return user_detail.get("mobile", self._getPhone())
Esempio n. 3
0
def _lookup_provider_policies(provider_type):
    """
    helper, to prevent deleting a provider while it is still used in a policy

    :param provider_type: the type of provider: sms or email
    :return: a dictionary with provider names as key and list of policy names
    """
    provider_policies = {}

    # lookup the policy action name
    provider_action_name = Policy_action_name.get(provider_type)
    if not provider_action_name:
        raise Exception('unknown provider_type for policy lookup! %r' %
                        provider_type)

    # now have a look at all authentication policies
    policies = linotp.lib.policy.getPolicy({
        'scope': 'authentication',
        "action": provider_action_name,
    })

    for policy in policies:

        provider_name = get_action_value(policy,
                                         scope='authentication',
                                         action=provider_action_name,
                                         default='')

        if provider_name not in provider_policies:
            provider_policies[provider_name] = []

        provider_policies[provider_name].append(policy)

    return provider_policies
Esempio n. 4
0
    def _get_email_address(self, user=None):
        '''
        get the email address
            - from the token info or
            - if the policy allowes it, from the user info
        '''

        if not user:
            return self._email_address

        pol = get_client_policy(context['Client'],
                                scope="authentication",
                                user=user,
                                action="dynamic_email_address")

        if not pol:
            return self._email_address

        get_dynamic = get_action_value(pol,
                                       scope="authentication",
                                       action="dynamic_email_address",
                                       default='')

        if not get_dynamic:
            return self._email_address

        user_detail = getUserDetail(user)
        return user_detail.get('email', self._email_address)
Esempio n. 5
0
def is_email_editable(user=""):
    """
    this function checks the policy scope=selfservice, action=edit_email
    This is a int policy, while the '0' is a deny
    """

    realm = user.realm
    login = user.login

    policies = get_client_policy(
        client=context["Client"],
        scope="selfservice",
        action="edit_email",
        realm=realm,
        user=login,
    )

    edit_email = get_action_value(policies,
                                  scope="selfservice",
                                  action="edit_email",
                                  default=1)

    if edit_email == 0:
        return False

    return True
Esempio n. 6
0
def is_phone_editable(user=""):
    """
    this function checks the policy scope=selfservice, action=edit_sms
    This is a int policy, while the '0' is a deny
    """
    # the default string is the OTP value
    ret = True
    realm = user.realm
    login = user.login

    policies = getPolicy(
        {
            "scope": "selfservice",
            "realm": realm,
            "action": "edit_sms",
            "user": login,
        }
    )

    edit_sms = get_action_value(
        policies, scope="selfservice", action="edit_sms", default=1
    )

    if edit_sms == 0:
        return False

    return True
Esempio n. 7
0
    def _getEmailSubject(self, user=""):
        """
        Could be used to implement some more complex logic similar to the
        SMS token where the SMS text is read from a policy.

        :return: The message that is sent to the user. It should contain
            at least the placeholder <otp>
        :rtype: string
        """
        subject = ''

        if not user:
            return subject

        realm = user.realm
        login = user.login

        policies = get_client_policy(context['Client'],
                                     scope="authentication",
                                     realm=realm,
                                     user=login,
                                     action="emailsubject")

        subject = get_action_value(policies,
                                   scope="authentication",
                                   action="emailsubject",
                                   default=subject)

        return subject
Esempio n. 8
0
def get_voice_message(user="", realm=""):
    """
    This function returns the voice message as defined in the policy
    authentication/voice_message. If no such policy is defined, the
    function returns the fallback message "{otp}"

    :return: string
    """

    voice_text = "{otp}"

    pol = get_client_policy(
        context["Client"],
        scope="authentication",
        realm=realm,
        user=user,
        action="voice_message",
    )

    if len(pol) > 0:
        voice_text = get_action_value(pol,
                                      scope="authentication",
                                      action="voice_message",
                                      default="")

        log.debug("[get_voice_message] got the voice_message = %s", voice_text)

    return voice_text
Esempio n. 9
0
def is_phone_editable(user=""):
    '''
    this function checks the policy scope=selfservice, action=edit_sms
    This is a int policy, while the '0' is a deny
    '''
    # the default string is the OTP value
    ret = True
    realm = user.realm
    login = user.login

    policies = getPolicy({
        'scope': 'selfservice',
        'realm': realm,
        "action": "edit_sms",
        "user": login
    })

    edit_sms = get_action_value(policies,
                                scope='selfservice',
                                action="edit_sms",
                                default=1)

    if edit_sms == 0:
        return False

    return True
Esempio n. 10
0
    def _getEmailMessage(self, user=""):
        """
        Could be used to implement some more complex logic similar to the
        SMS token where the SMS text is read from a policy.

        :return: The message that is sent to the user. It should contain
            at least the placeholder <otp>
        :rtype: string
        """
        message = DEFAULT_MESSAGE

        if not user:
            return message

        realm = user.realm
        login = user.login

        policies = get_client_policy(
            context["Client"],
            scope="authentication",
            realm=realm,
            user=login,
            action="emailtext",
        )

        message = get_action_value(
            policies,
            scope="authentication",
            action="emailtext",
            default=message,
        )

        return message
Esempio n. 11
0
def get_voice_language(user="", realm=""):
    """
    This function returns the voice language as defined in the policy
    authentication/voice_language. If no such policy is defined, the
    function returns the fallback message "en"

    :return: string
    """

    voice_language = "en"

    pol = get_client_policy(context['Client'],
                            scope="authentication",
                            realm=realm,
                            user=user,
                            action="voice_language")

    voice_language = get_action_value(pol,
                                      scope='authentication',
                                      action="voice_language",
                                      default='')

    log.debug("[get_voice_language] got the voice_language = %s",
              voice_language)

    return voice_language
Esempio n. 12
0
def check_maxtoken_for_user_by_type(user, type_of_token):
    '''
    This internal function checks the number of assigned tokens to a user
    restricted by the policies:

        "scope = enrollment", action = "maxtokenTOKENTYPE = <number>"

    :param user: to whom the token should belong
    :param type_of_token: which type of token should be enrolled or assigned
    :raises PolicyException: if maxtoken policy would be violated
    '''

    _ = context['translate']

    if not user or not user.login:
        return

    client = _get_client()

    user_realms = _getUserRealms(user)

    log.debug("checking the already assigned tokens for user %r, realms %s"
              % (user, user_realms))
    # ------------------------------------------------------------------ --

    # check the maxtokenTOKENTYPE policy

    typed_tokens = linotp.lib.token.getTokens4UserOrSerial(
                        user, token_type=type_of_token)

    for user_realm in user_realms:

        policies = get_client_policy(client,
                                     action="maxtoken%s" % type_of_token.upper(),
                                     scope='enrollment',
                                     realm=user_realm,
                                     user=user.login,
                                     userObj=user)

        if not policies:
            continue

        # compare the tokens of the user with the max numbers of the policy

        total_maxtoken = get_action_value(
            policies, scope='enrollment',
            action="maxtoken%s" % type_of_token.upper(), default=-1)

        if total_maxtoken == -1 or isinstance(total_maxtoken, bool):
            continue

        if len(typed_tokens) + 1 > total_maxtoken:

            error_msg = _("The maximum number of allowed tokens of type %s "
                          "per user is exceeded. Check the policies "
                          "scope=enrollment, action=maxtoken%s"
                          % (type_of_token, type_of_token.upper()))

            raise linotp.lib.policy.MaxTokenTypeUserPolicyException(error_msg)
Esempio n. 13
0
def get_provider_from_policy(provider_type,
                             realm=None,
                             user=None,
                             scope='authentication',
                             action=None):
    """
    interface for the provider user like email token or sms token

    :param provider_type: 'push', 'email' or 'sms
    :param user: the user, who should receive the message, used for
                 the policy lookup
    :return: the list of all identified providers by name
    """

    # check if the provider is defined in a policy
    provider_name = None

    # lookup the policy action name
    provider_action_name = Policy_action_name.get(provider_type)
    if not provider_action_name:
        raise Exception('unknown provider_type for policy lookup! %r' %
                        provider_type)

    if user is None:
        raise Exception('unknown user for policy lookup! %r' % user)

    if user and user.login:
        realm = user.realm

    if not action:
        action = provider_action_name

    policies = linotp.lib.policy.get_client_policy(request_context['Client'],
                                                   scope=scope,
                                                   action=action,
                                                   realm=realm,
                                                   user=user.login)

    if not policies:

        default_provider = _get_default_provider_name(provider_type)

        if default_provider:
            return [default_provider]

        return []

    provider_names = get_action_value(policies,
                                      scope=scope,
                                      action=action,
                                      default='')

    providers = []

    for entry in [x.strip() for x in provider_names.split(' ')]:
        if entry:
            providers.append(entry)

    return providers
Esempio n. 14
0
def check_maxtoken_for_user(user):
    '''
    This internal function checks the number of assigned tokens to a user
    restricted by the policies:

        "scope = enrollment", action = "maxtoken = <number>"

    :param user: to whom the token should belong
    :raises PolicyException: if maxtoken policy would be violated
    '''

    _ = context['translate']

    if not user or not user.login:
        return

    client = _get_client()

    user_realms = _getUserRealms(user)

    log.debug("checking the already assigned tokens for user %r, realms %s" %
              (user, user_realms))

    # ----------------------------------------------------------------------- --

    # check the maxtoken policy

    action = "maxtoken"
    tokens = linotp.lib.token.getTokens4UserOrSerial(user, "")

    for user_realm in user_realms:

        policies = get_client_policy(client,
                                     scope='enrollment',
                                     action=action,
                                     realm=user_realm,
                                     user=user.login,
                                     userObj=user)

        if not policies:
            continue

        total_maxtoken = get_action_value(policies,
                                          scope='enrollment',
                                          action=action,
                                          default=-1)

        if total_maxtoken == -1 or isinstance(total_maxtoken, bool):
            continue

        if len(tokens) + 1 > total_maxtoken:

            error_msg = _("The maximum number of allowed tokens "
                          "per user is exceeded. Check the "
                          "policies scope=enrollment, "
                          "action=maxtoken")

            raise linotp.lib.policy.MaxTokenUserPolicyException(error_msg)
Esempio n. 15
0
def notify_user(user, action, info, required=False):
    """
    notify user via email, sms or other method (http/whatsapp...)

    :param user: the user who should be notified
    :param action: action is currently the notification action like
                   enrollment, setPin, which are defined in the
                   notification policies
    :param info: generic dict which is action specific
    :param required: if True an exception is raised if no notification could
                     be send eg if no provider is defined or could be found

    :return: boolean - true if notification is enabled
    """

    policies = linotp.lib.policy.get_client_policy(
        request_context["Client"],
        scope="notification",
        action=action,
        realm=user.realm,
        user=user.login,
    )

    provider_specs = get_action_value(
        policies, scope="notification", action=action, default=""
    )

    if not isinstance(provider_specs, list):
        provider_specs = [provider_specs]

    # TODO: use the ResouceSchduler to handle failover

    for provider_spec in provider_specs:

        provider_type, _sep, provider_name = provider_spec.partition("::")

        if provider_type == "email":
            notify_user_by_email(provider_name, user, action, info)
            return True

        # elif provider_type == 'sms':
        #    notify_user_by_email(provider_name, user, action, info)

    log.info("Failed to notify user %r", user)

    if required:
        raise NotificationException(
            "No notification has been sent - %r provider defined?" % action
        )

    return False
Esempio n. 16
0
    def _is_valid_facet(self, origin):
        """
        check if origin is in the valid facets if the u2f_valid_facets policy is set.
        Otherwise check if the origin matches the previously saved origin

        :return:          boolean - True if supported, False if unsupported
        """
        is_valid = False

        # Get the valid facets as specified in the enrollment policy 'u2f_valid_facets'
        # for the specific realm
        valid_facets_action_value = ""
        realms = self.token.getRealmNames()
        if len(realms) > 0:
            get_policy_params = {
                "action": "u2f_valid_facets",
                "scope": "enrollment",
                "realm": realms[0],
            }
            policies = getPolicy(get_policy_params)
            valid_facets_action_value = get_action_value(
                policies,
                scope="enrollment",
                action="u2f_valid_facets",
                default="",
            )

        if valid_facets_action_value != "":
            # 'u2f_valid_facets' policy is set - check if origin is in valid facets list
            valid_facets = valid_facets_action_value.split(";")
            for facet in valid_facets:
                facet = facet.strip()
            if origin in valid_facets:
                is_valid = True
        else:
            # 'u2f_valid_facets' policy is empty or not set
            # check if origin matches the origin stored in the token info or save it if no origin
            # is stored yet
            appId = self._get_app_id()
            if appId == origin:
                is_valid = True

        return is_valid
Esempio n. 17
0
File: u2f.py Progetto: soitun/LinOTP
    def valid_facets(self, realm=None):
        """
        Show the JSON output for the valid facets configured by the enrollment
        policy 'u2f_valid_facets'. The form of the JSON output is specified by
        the FIDO Alliance.
        """
        if realm is None:
            realm = getDefaultRealm()

        # Get the valid facets as specified in the enrollment policy 'u2f_valid_facets'
        # for the specific realm
        get_policy_params = {
            "action": "u2f_valid_facets",
            "scope": "enrollment",
            "realm": realm,
        }
        valid_facets_action_value = get_action_value(
            getPolicy(get_policy_params),
            scope="enrollment",
            action="u2f_valid_facets",
            default="",
        )
        # the action value contains the semicolon-separated list of valid
        # facets
        valid_facets = valid_facets_action_value.split(";")

        # Prepare the response
        response.content_type = (
            "application/fido.trusted-­apps+json"  # as specified by FIDO
        )
        response_dict = {
            "trustedFacets": [{
                "version": {
                    "major": 1,
                    "minor": 0
                },
                "ids": []
            }]
        }
        for facet in valid_facets:
            facet = facet.strip()
            response_dict["trustedFacets"][0]["ids"].append(facet)
        return json.dumps(response_dict)
Esempio n. 18
0
def loadProviderFromPolicy(provider_type, realm=None, user=None):
    """
    interface for the provider user like email token or sms token

    :param provider_type: 'push', 'email' or 'sms
    :param user: the user, who should receive the message, used for
                 the policy lookup
    :return: the instantiated provider with already loaded config
    """

    # check if the provider is defined in a policy
    provider_name = None

    # lookup the policy action name
    provider_action_name = Policy_action_name.get(provider_type)
    if not provider_action_name:
        raise Exception("unknown provider_type for policy lookup! %r" %
                        provider_type)

    if user is None:
        raise Exception("unknown user for policy lookup! %r" % user)

    if user and user.login:
        realm = user.realm

    policies = linotp.lib.policy.get_client_policy(
        request_context["Client"],
        scope="authentication",
        action=provider_action_name,
        realm=realm,
        user=user.login,
    )

    provider_name = get_action_value(
        policies,
        scope="authentication",
        action=provider_action_name,
        default="",
    )

    return loadProvider(provider_type, provider_name)
Esempio n. 19
0
def get_auth_smstext(user="", realm=""):
    '''
    this function checks the policy scope=authentication, action=smstext
    This is a string policy
    The function returns the tuple (bool, string),
        bool: If a policy is defined
        string: the string to use
    '''
    pol = get_client_policy(context['Client'],
                            scope="authentication",
                            realm=realm,
                            user=user,
                            action="smstext")

    smstext = get_action_value(pol,
                               scope='authentication',
                               action="smstext",
                               default="<otp>")

    log.debug("[get_auth_smstext] got the smstext = %s" % smstext)

    return (smstext != "<otp>"), smstext
Esempio n. 20
0
File: u2f.py Progetto: ppires/LinOTP
    def valid_facets(self, realm=None):
        """
        Show the JSON output for the valid facets configured by the enrollment
        policy 'u2f_valid_facets'. The form of the JSON output is specified by
        the FIDO Alliance.
        """
        if realm is None:
            realm = getDefaultRealm()

        # Get the valid facets as specified in the enrollment policy 'u2f_valid_facets'
        # for the specific realm
        get_policy_params = {
            'action': 'u2f_valid_facets',
            'scope': 'enrollment',
            'realm': realm
        }
        valid_facets_action_value = get_action_value(
            getPolicy(get_policy_params),
            scope='enrollment',
            action='u2f_valid_facets',
            default='')
        # the action value contains the semicolon-separated list of valid facets
        valid_facets = valid_facets_action_value.split(';')

        # Prepare the response
        response.content_type = 'application/fido.trusted-­apps+json'  # as specified by FIDO
        response_dict = {
            "trustedFacets": [{
                "version": {
                    "major": 1,
                    "minor": 0
                },
                "ids": []
            }]
        }
        for facet in valid_facets:
            facet = facet.strip()
            response_dict['trustedFacets'][0]['ids'].append(facet)
        return json.dumps(response_dict)
Esempio n. 21
0
def enforce_smstext(user="", realm=""):
    '''
    this function checks the boolean policy
                            scope=authentication,
                            action=enforce_smstext

    The function returns true if the smstext should be used instead of the
    challenge data
    :return: bool
    '''
    pol = get_client_policy(context['Client'],
                            scope="authentication",
                            realm=realm,
                            user=user,
                            action="enforce_smstext")

    enforce_smstext = get_action_value(pol,
                                       scope='authentication',
                                       action="enforce_smstext",
                                       default=False)
    log.debug("got enforce_smstext = %r" % enforce_smstext)

    return enforce_smstext
Esempio n. 22
0
    def getInitDetail(self, params, user=None):
        """
        to complete the token normalisation, the response of the initialisation
        should be built by the token specific method, the getInitDetails
        """
        response_detail = {}

        info = self.getInfo()
        response_detail.update(info)
        response_detail['serial'] = self.getSerial()

        # get requested phase
        try:
            requested_phase = params["phase"]
        except KeyError:
            raise ParameterError("Missing parameter: 'phase'")

        if requested_phase == "registration1":
            # We are in registration phase 1
            # We create a 32 bytes otp key (from urandom)
            # which is used as the registration challenge
            challenge = base64.urlsafe_b64encode(
                binascii.unhexlify(self._genOtpKey_(32)))
            self.addToTokenInfo('challenge', challenge.decode('ascii'))

            # save the appId to the TokenInfo
            # An appId passed as parameter is preferred over an appId defined in a policy
            appId = ''
            if 'appid' in params:
                appId = params.get('appid')
            else:
                # No appId passed as parameter - fall back to the policy
                # Get the appId as specified in the enrollment policy 'u2f_app_id'
                # for the specific realm
                # If the token has multiple realms, the appIds are checked for conflicts.
                # It could be discussed whether the token should use the appId of the default
                # realm, when the token is not attached to any realms
                realms = self.token.getRealmNames()
                for realm in realms:
                    get_policy_params = {
                        'action': 'u2f_app_id',
                        'scope': 'enrollment',
                        'realm': realm
                    }
                    policies = getPolicy(get_policy_params)
                    policy_value = get_action_value(policies,
                                                    scope='enrollment',
                                                    action='u2f_app_id',
                                                    default='')

                    # Check for appId conflicts
                    if appId and policy_value:
                        if appId != policy_value:
                            raise Exception(
                                "Conflicting appId values in u2f policies.")
                    appId = policy_value

            if not appId:
                raise Exception("No appId defined.")
            self.addToTokenInfo('appId', appId)

            # create U2F RegisterRequest object and append it to the response as 'message'
            appId = self._get_app_id()
            register_request = {
                'challenge': challenge.decode('ascii'),
                'version': 'U2F_V2',
                'appId': appId
            }
            response_detail['registerrequest'] = register_request

        elif requested_phase == "registration2":
            # We are in registration phase 2
            # process the data generated by the u2f compatible token device
            registerResponse = ""

            otpkey = None
            if 'otpkey' in params:
                otpkey = params.get('otpkey')

            if otpkey is not None:
                # otpkey holds the JSON RegisterResponse object as specified by the FIDO Alliance
                try:
                    registerResponse = json.loads(otpkey)
                except ValueError as ex:
                    raise Exception('Invalid JSON format')

                self._handle_client_errors(registerResponse)

                try:
                    registrationData = registerResponse['registrationData']
                    clientData = registerResponse['clientData']
                except AttributeError as ex:
                    raise Exception("Couldn't find keyword in JSON object")

                # registrationData and clientData are urlsafe base64 encoded
                # correct padding errors (length should be multiples of 4)
                # fill up the registrationData with '=' to the correct padding
                registrationData = registrationData + \
                    ('=' * (4 - (len(registrationData) % 4)))
                clientData = clientData + ('=' * (4 - (len(clientData) % 4)))
                registrationData = base64.urlsafe_b64decode(
                    registrationData.encode('ascii'))
                clientData = base64.urlsafe_b64decode(
                    clientData.encode('ascii'))

                # parse the raw registrationData according to the specification
                (userPublicKey, keyHandle, x509cert, signature) = \
                    self._parseRegistrationData(registrationData)

                # check the received clientData object
                if not self._checkClientData(
                        clientData, 'registration',
                        self.getFromTokenInfo('challenge', None)):
                    raise ValueError(
                        "Received invalid clientData object. Aborting...")

                # prepare the applicationParameter and challengeParameter needed for
                # verification of the registration signature
                appId = self._get_app_id()
                applicationParameter = sha256(appId.encode('utf-8')).digest()
                challengeParameter = sha256(clientData).digest()

                # verify the registration signature
                self._validateRegistrationSignature(applicationParameter,
                                                    challengeParameter,
                                                    keyHandle, userPublicKey,
                                                    x509cert, signature)

                # save the key handle and the user public key in the Tokeninfo field for
                # future use
                self.addToTokenInfo(
                    'keyHandle',
                    base64.urlsafe_b64encode(keyHandle).decode('ascii'))
                self.addToTokenInfo(
                    'publicKey',
                    base64.urlsafe_b64encode(userPublicKey).decode('ascii'))
                self.addToTokenInfo('counter', '0')
                self.addToTokenInfo('phase', 'authentication')
                # remove the registration challenge from the token info
                self.removeFromTokenInfo('challenge')
                # Activate the token
                self.token.LinOtpIsactive = True
            else:
                raise ValueError("No otpkey set")
        else:
            raise Exception("Unsupported phase: %s", requested_phase)

        return response_detail