def test_03_authenticate(self):
        init_token({"type": "pw",
                    "otpkey": "password1",
                    "pin": "pin1"},
                   user=User("cornelius", self.realm1))

        init_token({"type": "pw",
                    "otpkey": "password2",
                    "pin": "pin2"},
                   user=User("cornelius", self.realm1))

        init_token({"type": "pw",
                    "otpkey": "password3",
                    "pin": "pin3"},
                   user=User("cornelius", self.realm1))

        init_token({"serial": "eye1",
                    "type": "4eyes",
                    "4eyes": "%s:2" % self.realm1,
                    "separator": " "})

        r = check_serial_pass("eye1", "pin1password1 pin2password2")
        self.assertEqual(r[0], True)

        r = check_serial_pass("eye1", "pin1password1")
        self.assertEqual(r[0], False)
        self.assertEqual(r[1].get("foureyes"), "Only found 1 tokens in realm "
                                               "realm1")
Beispiel #2
0
    def test_03_authenticate(self):
        init_token({"type": "pw",
                    "otpkey": "password1",
                    "pin": "pin1"},
                   user=User("cornelius", self.realm1))

        init_token({"type": "pw",
                    "otpkey": "password2",
                    "pin": "pin2"},
                   user=User("cornelius", self.realm1))

        init_token({"type": "pw",
                    "otpkey": "password3",
                    "pin": "pin3"},
                   user=User("cornelius", self.realm1))

        init_token({"serial": "eye1",
                    "type": "4eyes",
                    "4eyes": "{0!s}:2".format(self.realm1),
                    "separator": " "})

        r = check_serial_pass("eye1", "pin1password1 pin2password2")
        self.assertEqual(r[0], True)

        r = check_serial_pass("eye1", "pin1password1")
        self.assertEqual(r[0], False)
        self.assertEqual(r[1].get("foureyes"), "Only found 1 tokens in realm "
                                               "realm1")
    def test_01_challenge(self):

        set_policy("chalresp", scope=SCOPE.AUTHZ,
                   action="{0!s}=hotp".format(ACTION.CHALLENGERESPONSE))
        token = init_token({"genkey": 1, "serial": "CHAL1", "pin": "pin"})
        from privacyidea.lib.token import check_serial_pass
        r = check_serial_pass(token.token.serial, "pin")
        # The OTP PIN is correct
        self.assertEqual(r[0], False)
        self.assertEqual(r[1].get("message"), "please enter otp: ")
        transaction_id = r[1].get("transaction_id")
        chals = get_challenges()
        self.assertEqual(len(chals), 1)
        self.assertEqual(chals[0].transaction_id, transaction_id)

        # get challenge for this serial
        chals = get_challenges(serial="CHAL1")
        self.assertEqual(len(chals), 1)
        self.assertEqual(chals[0].transaction_id, transaction_id)

        # get challenge for another seial
        chals = get_challenges(serial="CHAL2")
        self.assertEqual(len(chals), 0)

        delete_policy("chalresp")
Beispiel #4
0
    def test_01_challenge(self):

        set_policy("chalresp",
                   scope=SCOPE.AUTHZ,
                   action="{0!s}=hotp".format(ACTION.CHALLENGERESPONSE))
        token = init_token({"genkey": 1, "serial": "CHAL1", "pin": "pin"})
        from privacyidea.lib.token import check_serial_pass
        r = check_serial_pass(token.token.serial, "pin")
        # The OTP PIN is correct
        self.assertEqual(r[0], False)
        self.assertEqual(r[1].get("message"), _("please enter otp: "))
        transaction_id = r[1].get("transaction_id")
        chals = get_challenges()
        self.assertEqual(len(chals), 1)
        self.assertEqual(chals[0].transaction_id, transaction_id)

        # get challenge for this serial
        chals = get_challenges(serial="CHAL1")
        self.assertEqual(len(chals), 1)
        self.assertEqual(chals[0].transaction_id, transaction_id)

        # get challenge for another seial
        chals = get_challenges(serial="CHAL2")
        self.assertEqual(len(chals), 0)

        delete_policy("chalresp")
Beispiel #5
0
    def test_37_challenge(self):
        # We create a challenge by first sending the PIN of the HOTP token
        # then we answer the challenge by sending the OTP.

        num1 = Challenge.query.filter(Challenge.serial == "hotptoken").count()
        # The correct PIN will create a challenge
        r, reply = check_serial_pass("hotptoken", "hotppin")
        self.assertTrue(r is False, r)
        num2 = Challenge.query.filter(Challenge.serial == "hotptoken").count()
        # check that the challenge is created
        self.assertTrue(num1 + 1 == num2, (num1, num2))
        self.assertTrue(type(reply) == dict, reply)
        transaction_id = reply.get("transaction_id", "")
        self.assertTrue(len(transaction_id) > 10, reply)

        # Challenge Response, with the transaction id
        r, reply = check_serial_pass("hotptoken", "436521",
                                     {"transaction_id": transaction_id})
        self.assertTrue(r)
        self.assertTrue(
            reply.get("message") == "Found matching challenge", reply)

        # create two tokens with the same OTP Key and the same PIN, so
        # this token will create the same challenge
        # creating a challenge will not work!
        tokenobject = init_token({
            "serial": "CHALL001",
            "type": "hotp",
            "otpkey": self.otpkey
        })
        tokenobject = init_token({
            "serial": "CHALL002",
            "type": "hotp",
            "otpkey": self.otpkey
        })
        user = User("cornelius", realm=self.realm1)
        assign_token("CHALL001", user)
        assign_token("CHALL002", user)
        set_pin("CHALL001", "challpin")
        set_pin("CHALL002", "challpin")
        r, reply = check_user_pass(user, "challpin")
        self.assertFalse(r)
        self.assertTrue(
            "Multiple tokens to create a challenge found"
            in reply.get("message"), reply)
        remove_token("CHALL001")
        remove_token("CHALL002")
    def test_35_check_serial_pass(self):
        hotp_tokenobject = get_tokens(serial="hotptoken")[0]
        hotp_tokenobject.set_pin("hotppin")
        hotp_tokenobject.save()

        r, reply = check_serial_pass("XXXXXXXXX", "password")
        self.assertFalse(r)

        #r = get_multi_otp("hotptoken", count=20)
        #self.assertTrue(r == 0, r)
        # 0: '520489', 1: '403154', 2: '481090', 3: '868912',
        # 4: '736127', 5: '229903', 6: '436521', 7: '186581',
        # 8: '447589', 9: '903435', 10: '578337', 11: '328281',
        # 12: '191635', 13: '184416', 14: '574561', 15: '797908'
        r, reply = check_serial_pass("hotptoken", "hotppin481090")
        self.assertTrue(r)
        # the same OTP value  must not match!
        # cko
        r, reply = check_serial_pass("hotptoken", "hotppin481090")
        self.assertFalse(r)
Beispiel #7
0
    def test_35_check_serial_pass(self):
        hotp_tokenobject = get_tokens(serial="hotptoken")[0]
        hotp_tokenobject.set_pin("hotppin")
        hotp_tokenobject.save()

        r, reply = check_serial_pass("XXXXXXXXX", "password")
        self.assertFalse(r)

        #r = get_multi_otp("hotptoken", count=20)
        #self.assertTrue(r == 0, r)
        # 0: '520489', 1: '403154', 2: '481090', 3: '868912',
        # 4: '736127', 5: '229903', 6: '436521', 7: '186581',
        # 8: '447589', 9: '903435', 10: '578337', 11: '328281',
        # 12: '191635', 13: '184416', 14: '574561', 15: '797908'
        r, reply = check_serial_pass("hotptoken", "hotppin481090")
        self.assertTrue(r)
        # the same OTP value  must not match!
        # cko
        r, reply = check_serial_pass("hotptoken", "hotppin481090")
        self.assertFalse(r)
    def test_37_challenge(self):
        # We create a challenge by first sending the PIN of the HOTP token
        # then we answer the challenge by sending the OTP.

        num1 = Challenge.query.filter(Challenge.serial == "hotptoken").count()
        # The correct PIN will create a challenge
        r, reply = check_serial_pass("hotptoken", "hotppin")
        self.assertTrue(r is False, r)
        num2 = Challenge.query.filter(Challenge.serial == "hotptoken").count()
        # check that the challenge is created
        self.assertTrue(num1 + 1 == num2, (num1, num2))
        self.assertTrue(type(reply) == dict, reply)
        transaction_id = reply.get("transaction_id","")
        self.assertTrue(len(transaction_id) > 10, reply)

        # Challenge Response, with the transaction id
        r, reply = check_serial_pass("hotptoken", "436521",
                                     {"transaction_id": transaction_id})
        self.assertTrue(r)
        self.assertTrue(reply.get("message") == "Found matching challenge",
                        reply)

        # create two tokens with the same OTP Key and the same PIN, so
        # this token will create the same challenge
        # creating a challenge will not work!
        tokenobject = init_token({"serial": "CHALL001", "type": "hotp",
                                  "otpkey": self.otpkey})
        tokenobject = init_token({"serial": "CHALL002", "type": "hotp",
                                  "otpkey": self.otpkey})
        user = User("cornelius", realm=self.realm1)
        assign_token("CHALL001", user)
        assign_token("CHALL002", user)
        set_pin("CHALL001", "challpin")
        set_pin("CHALL002", "challpin")
        r, reply = check_user_pass(user, "challpin")
        self.assertFalse(r)
        self.assertTrue("Multiple tokens to create a challenge found"
                        in reply.get("message"), reply)
        remove_token("CHALL001")
        remove_token("CHALL002")
Beispiel #9
0
def check():
    """
    check the authentication for a user or a serial number.
    Either a ``serial`` or a ``user`` is required to authenticate.
    The PIN and OTP value is sent in the parameter ``pass``.
    In case of successful authentication it returns ``result->value: true``.

    In case of a challenge response authentication a parameter ``exception=1``
    can be passed. This would result in a HTTP 500 Server Error response if
    an error occurred during sending of SMS or Email.

    In case ``/validate/radiuscheck`` is requested, the responses are
    modified as follows: A successful authentication returns an empty HTTP
    204 response. An unsuccessful authentication returns an empty HTTP
    400 response. Error responses are the same responses as for the
    ``/validate/check`` endpoint.

    :param serial: The serial number of the token, that tries to authenticate.
    :param user: The loginname/username of the user, who tries to authenticate.
    :param realm: The realm of the user, who tries to authenticate. If the
        realm is omitted, the user is looked up in the default realm.
    :param pass: The password, that consists of the OTP PIN and the OTP value.
    :param otponly: If set to 1, only the OTP value is verified. This is used
        in the management UI. Only used with the parameter serial.
    :param transaction_id: The transaction ID for a response to a challenge
        request
    :param state: The state ID for a response to a challenge request

    :return: a json result with a boolean "result": true

    **Example Validation Request**:

        .. sourcecode:: http

           POST /validate/check HTTP/1.1
           Host: example.com
           Accept: application/json

           user=user
           realm=realm1
           pass=s3cret123456

    **Example response** for a successful authentication:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "message": "matching 1 tokens",
                "serial": "PISP0000AB00",
                "type": "spass"
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": true
              },
              "version": "privacyIDEA unknown"
            }

    **Example response** for this first part of a challenge response
    authentication:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "serial": "PIEM0000AB00",
                "type": "email",
                "transaction_id": "12345678901234567890",
                "multi_challenge: [ {"serial": "PIEM0000AB00",
                                     "transaction_id":  "12345678901234567890",
                                     "message": "Please enter otp from your
                                     email"},
                                    {"serial": "PISM12345678",
                                     "transaction_id": "12345678901234567890",
                                     "message": "Please enter otp from your
                                     SMS"}
                ]
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": false
              },
              "version": "privacyIDEA unknown"
            }

    In this example two challenges are triggered, one with an email and one
    with an SMS. The application and thus the user has to decide, which one
    to use. They can use either.

    .. note:: All challenge response tokens have the same transaction_id in
       this case.
    """
    #user = get_user_from_param(request.all_data)
    user = request.User
    serial = getParam(request.all_data, "serial")
    password = getParam(request.all_data, "pass", required)
    otp_only = getParam(request.all_data, "otponly")
    options = {"g": g,
               "clientip": g.client_ip}
    # 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

    g.audit_object.log({"user": user.login,
                        "resolver": user.resolver,
                        "realm": user.realm})

    if serial:
        if not otp_only:
            result, details = check_serial_pass(serial, password, options=options)
        else:
            result, details = check_otp(serial, password)

    else:
        result, details = check_user_pass(user, password, options=options)

    g.audit_object.log({"info": details.get("message"),
                        "success": result,
                        "serial": serial or details.get("serial"),
                        "tokentype": details.get("type")})
    return send_result(result, details=details)
 def _step2():
     # correct PIN, wrong OTP
     return check_serial_pass(self.serial2, "{}123456".format(self.otppin))
Beispiel #11
0
def check():
    """
    check the authentication for a user or a serial number.
    Either a ``serial`` or a ``user`` is required to authenticate.
    The PIN and OTP value is sent in the parameter ``pass``.

    :param serial: The serial number of the token, that tries to authenticate.
    :param user: The loginname/username of the user, who tries to authenticate.
    :param realm: The realm of the user, who tries to authenticate. If the
        realm is omitted, the user is looked up in the default realm.
    :param pass: The password, that consists of the OTP PIN and the OTP value.
    :param transaction_id: The transaction ID for a response to a challenge
        request
    :param state: The state ID for a response to a challenge request

    :return: a json result with a boolean "result": true

    **Example response** for a successful authentication:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "message": "matching 1 tokens",
                "serial": "PISP0000AB00",
                "type": "spass"
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": true
              },
              "version": "privacyIDEA unknown"
            }
    """
    user = get_user_from_param(request.all_data)
    serial = getParam(request.all_data, "serial")
    password = getParam(request.all_data, "pass", required)
    options = {"g": g, "clientip": g.client_ip}
    # 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

    g.audit_object.log({"user": user.login, "realm": user.realm})

    if serial:
        result, details = check_serial_pass(serial, password, options=options)
    else:
        result, details = check_user_pass(user, password, options=options)

    g.audit_object.log({
        "info": details.get("message"),
        "success": result,
        "serial": serial or details.get("serial"),
        "tokentype": details.get("type")
    })
    return send_result(result, details=details)
Beispiel #12
0
def check():
    """
    check the authentication for a user or a serial number.
    Either a ``serial`` or a ``user`` is required to authenticate.
    The PIN and OTP value is sent in the parameter ``pass``.

    :param serial: The serial number of the token, that tries to authenticate.
    :param user: The loginname/username of the user, who tries to authenticate.
    :param realm: The realm of the user, who tries to authenticate. If the
        realm is omitted, the user is looked up in the default realm.
    :param pass: The password, that consists of the OTP PIN and the OTP value.
    :param transaction_id: The transaction ID for a response to a challenge
        request
    :param state: The state ID for a response to a challenge request

    :return: a json result with a boolean "result": true

    **Example response** for a successful authentication:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "message": "matching 1 tokens",
                "serial": "PISP0000AB00",
                "type": "spass"
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": true
              },
              "version": "privacyIDEA unknown"
            }
    """
    user = get_user_from_param(request.all_data)
    serial = getParam(request.all_data, "serial")
    password = getParam(request.all_data, "pass", required)
    options = {"g": g,
               "clientip": request.remote_addr}
    # 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

    g.audit_object.log({"user": user.login,
                        "realm": user.realm})

    if serial:
        result, details = check_serial_pass(serial, password, options=options)
    else:
        result, details = check_user_pass(user, password, options=options)

    g.audit_object.log({"info": details.get("message"),
                        "success": result,
                        "serial": serial or details.get("serial"),
                        "tokentype": details.get("type")})
    return send_result(result, details=details)
 def _step2():
     # correct PIN, wrong OTP
     return check_serial_pass(self.serial2,
                              "{}123456".format(self.otppin))
Beispiel #14
0
def check():
    """
    check the authentication for a user or a serial number.
    Either a ``serial`` or a ``user`` is required to authenticate.
    The PIN and OTP value is sent in the parameter ``pass``.
    In case of successful authentication it returns ``result->value: true``.

    :param serial: The serial number of the token, that tries to authenticate.
    :param user: The loginname/username of the user, who tries to authenticate.
    :param realm: The realm of the user, who tries to authenticate. If the
        realm is omitted, the user is looked up in the default realm.
    :param pass: The password, that consists of the OTP PIN and the OTP value.
    :param otponly: If set to 1, only the OTP value is verified. This is used
        in the management UI. Only used with the parameter serial.
    :param transaction_id: The transaction ID for a response to a challenge
        request
    :param state: The state ID for a response to a challenge request

    :return: a json result with a boolean "result": true

    **Example Validation Request**:

        .. sourcecode:: http

           POST /validate/check HTTP/1.1
           Host: example.com
           Accept: application/json

           user=user
           realm=realm1
           pass=s3cret123456

    **Example response** for a successful authentication:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "message": "matching 1 tokens",
                "serial": "PISP0000AB00",
                "type": "spass"
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": true
              },
              "version": "privacyIDEA unknown"
            }

    **Example response** for this first part of a challenge response
    authentication:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "serial": "PIEM0000AB00",
                "type": "email",
                "transaction_id": "12345678901234567890",
                "multi_challenge: [ {"serial": "PIEM0000AB00",
                                     "transaction_id":  "12345678901234567890",
                                     "message": "Please enter otp from your
                                     email"},
                                    {"serial": "PISM12345678",
                                     "transaction_id": "12345678901234567890",
                                     "message": "Please enter otp from your
                                     SMS"}
                ]
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": false
              },
              "version": "privacyIDEA unknown"
            }

    In this example two challenges are triggered, one with an email and one
    with an SMS. The application and thus the user has to decide, which one
    to use. They can use either.

    .. note:: All challenge response tokens have the same transaction_id in
       this case.
    """
    #user = get_user_from_param(request.all_data)
    user = request.User
    serial = getParam(request.all_data, "serial")
    password = getParam(request.all_data, "pass", required)
    otp_only = getParam(request.all_data, "otponly")
    options = {"g": g, "clientip": g.client_ip}
    # 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

    g.audit_object.log({
        "user": user.login,
        "resolver": user.resolver,
        "realm": user.realm
    })

    if serial:
        if not otp_only:
            result, details = check_serial_pass(serial,
                                                password,
                                                options=options)
        else:
            result, details = check_otp(serial, password)

    else:
        result, details = check_user_pass(user, password, options=options)

    g.audit_object.log({
        "info": details.get("message"),
        "success": result,
        "serial": serial or details.get("serial"),
        "tokentype": details.get("type")
    })
    return send_result(result, details=details)
Beispiel #15
0
def check():
    """
    check the authentication for a user or a serial number.
    Either a ``serial`` or a ``user`` is required to authenticate.
    The PIN and OTP value is sent in the parameter ``pass``.
    In case of successful authentication it returns ``result->value: true``.

    In case of a challenge response authentication a parameter ``exception=1``
    can be passed. This would result in a HTTP 500 Server Error response if
    an error occurred during sending of SMS or Email.

    In case ``/validate/radiuscheck`` is requested, the responses are
    modified as follows: A successful authentication returns an empty ``HTTP
    204`` response. An unsuccessful authentication returns an empty ``HTTP
    400`` response. Error responses are the same responses as for the
    ``/validate/check`` endpoint.

    :param serial: The serial number of the token, that tries to authenticate.
    :param user: The loginname/username of the user, who tries to authenticate.
    :param realm: The realm of the user, who tries to authenticate. If the
        realm is omitted, the user is looked up in the default realm.
    :param type: The tokentype of the tokens, that are taken into account during
        authentication. Requires the *authz* policy :ref:`application_tokentype_policy`.
        It is ignored when a distinct serial is given.
    :param pass: The password, that consists of the OTP PIN and the OTP value.
    :param otponly: If set to 1, only the OTP value is verified. This is used
        in the management UI. Only used with the parameter serial.
    :param transaction_id: The transaction ID for a response to a challenge
        request
    :param state: The state ID for a response to a challenge request

    :return: a json result with a boolean "result": true

    **Example Validation Request**:

        .. sourcecode:: http

            POST /validate/check HTTP/1.1
            Host: example.com
            Accept: application/json

            user=user
            realm=realm1
            pass=s3cret123456

    **Example response** for a successful authentication:

        .. sourcecode:: http

            HTTP/1.1 200 OK
            Content-Type: application/json

            {
              "detail": {
                "message": "matching 1 tokens",
                "serial": "PISP0000AB00",
                "type": "spass"
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": true
              },
              "version": "privacyIDEA unknown"
            }

    **Example response** for this first part of a challenge response authentication:

        .. sourcecode:: http

            HTTP/1.1 200 OK
            Content-Type: application/json

            {
              "detail": {
                "serial": "PIEM0000AB00",
                "type": "email",
                "transaction_id": "12345678901234567890",
                "multi_challenge: [ {"serial": "PIEM0000AB00",
                                     "transaction_id":  "12345678901234567890",
                                     "message": "Please enter otp from your
                                     email",
                                     "client_mode": "interactive"},
                                    {"serial": "PISM12345678",
                                     "transaction_id": "12345678901234567890",
                                     "message": "Please enter otp from your
                                     SMS",
                                     "client_mode": "interactive"}
                ]
              },
              "id": 2,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": false
              },
              "version": "privacyIDEA unknown"
            }

    In this example two challenges are triggered, one with an email and one
    with an SMS. The application and thus the user has to decide, which one
    to use. They can use either.

    The challenges also contain the information of the "client_mode". This
    tells the plugin, whether it should display an input field to ask for the
    OTP value or e.g. to poll for an answered authentication.
    Read more at :ref:`client_modes`.

    .. note:: All challenge response tokens have the same ``transaction_id`` in
       this case.


    **Example response** for a successful authentication with ``/samlcheck``:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "message": "matching 1 tokens",
                "serial": "PISP0000AB00",
                "type": "spass"
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": {"attributes": {
                            "username": "******",
                            "realm": "themis",
                            "mobile": null,
                            "phone": null,
                            "myOwn": "/data/file/home/koelbel",
                            "resolver": "themis",
                            "surname": "Kölbel",
                            "givenname": "Cornelius",
                            "email": null},
                          "auth": true}
              },
              "version": "privacyIDEA unknown"
            }

    The response in ``value->attributes`` can contain additional attributes
    (like "myOwn") which you can define in the LDAP resolver in the attribute
    mapping.
    """
    user = request.User
    serial = getParam(request.all_data, "serial")
    password = getParam(request.all_data, "pass", required)
    otp_only = getParam(request.all_data, "otponly")
    token_type = getParam(request.all_data, "type")
    options = {"g": g, "clientip": g.client_ip, "user": user}
    # Add all params to the options
    for key, value in request.all_data.items():
        if value and key not in ["g", "clientip", "user"]:
            options[key] = value

    g.audit_object.log({
        "user": user.login,
        "resolver": user.resolver,
        "realm": user.realm
    })

    if serial:
        if user:
            # check if the given token belongs to the user
            if not get_tokens(user=user, serial=serial, count=True):
                raise ParameterError(
                    'Given serial does not belong to given user!')
        if not otp_only:
            success, details = check_serial_pass(serial,
                                                 password,
                                                 options=options)
        else:
            success, details = check_otp(serial, password)
        result = success

    else:
        options["token_type"] = token_type
        success, details = check_user_pass(user, password, options=options)
        result = success
        if request.path.endswith("samlcheck"):
            ui = user.info
            result = {"auth": success, "attributes": {}}
            if return_saml_attributes():
                if success or return_saml_attributes_on_fail():
                    # privacyIDEA's own attribute map
                    result["attributes"] = {
                        "username": ui.get("username"),
                        "realm": user.realm,
                        "resolver": user.resolver,
                        "email": ui.get("email"),
                        "surname": ui.get("surname"),
                        "givenname": ui.get("givenname"),
                        "mobile": ui.get("mobile"),
                        "phone": ui.get("phone")
                    }
                    # additional attributes
                    for k, v in ui.items():
                        result["attributes"][k] = v

    g.audit_object.log({
        "info": log_used_user(user, details.get("message")),
        "success": success,
        "serial": serial or details.get("serial"),
        "token_type": details.get("type")
    })
    return send_result(result, rid=2, details=details)
    def test_03_authenticate(self):
        self.setUp_user_realms()
        init_token(
            {
                "type": "pw",
                "otpkey": "password1",
                "pin": "pin1",
                "serial": "pwserial1"
            },
            user=User("cornelius", self.realm1))

        init_token(
            {
                "type": "pw",
                "otpkey": "password2",
                "pin": "pin2",
                "serial": "pwserial2"
            },
            user=User("cornelius", self.realm1))

        init_token(
            {
                "type": "pw",
                "otpkey": "password3",
                "pin": "pin3",
                "serial": "pwserial3"
            },
            user=User("cornelius", self.realm1))

        tok = init_token({
            "serial": "eye1",
            "type": "4eyes",
            "4eyes": "{0!s}:2".format(self.realm1),
            "separator": " "
        })

        r = check_serial_pass("eye1", "pin1password1 pin2password2")
        self.assertEqual(r[0], True)

        r = check_serial_pass("eye1", "pin1password1")
        self.assertEqual(r[0], False)
        self.assertEqual(r[1].get("foureyes"), "Only found 1 tokens in realm "
                         "realm1")

        # check false separator
        r = check_serial_pass("eye1", "pin1password1:pin2password2")
        self.assertFalse(r[0])
        self.assertEqual(r[1].get("foureyes"), "Only found 0 tokens in realm "
                         "realm1")

        # check authentication also works if the 4eyes-token is in the same realm
        tok.add_user(User('cornelius', self.realm1))
        r = check_serial_pass("eye1", "pin3password3 pin2password2")
        self.assertTrue(r[0])
        self.assertEqual(r[1].get('message'), 'matching 1 tokens')

        # cleanup
        remove_token(serial='pwserial1')
        remove_token(serial='pwserial2')
        remove_token(serial='pwserial3')
        remove_token(serial='eye1')
Beispiel #17
0
def check():
    """
    check the authentication for a user or a serial number.
    Either a ``serial`` or a ``user`` is required to authenticate.
    The PIN and OTP value is sent in the parameter ``pass``.
    In case of successful authentication it returns ``result->value: true``.

    In case of a challenge response authentication a parameter ``exception=1``
    can be passed. This would result in a HTTP 500 Server Error response if
    an error occurred during sending of SMS or Email.

    In case ``/validate/radiuscheck`` is requested, the responses are
    modified as follows: A successful authentication returns an empty HTTP
    204 response. An unsuccessful authentication returns an empty HTTP
    400 response. Error responses are the same responses as for the
    ``/validate/check`` endpoint.

    :param serial: The serial number of the token, that tries to authenticate.
    :param user: The loginname/username of the user, who tries to authenticate.
    :param realm: The realm of the user, who tries to authenticate. If the
        realm is omitted, the user is looked up in the default realm.
    :param type: The tokentype of the tokens, that are taken into account during
        authentication. Requires authz policy application_tokentype.
        Is ignored when a distinct serial is given.
    :param pass: The password, that consists of the OTP PIN and the OTP value.
    :param otponly: If set to 1, only the OTP value is verified. This is used
        in the management UI. Only used with the parameter serial.
    :param transaction_id: The transaction ID for a response to a challenge
        request
    :param state: The state ID for a response to a challenge request

    :return: a json result with a boolean "result": true

    **Example Validation Request**:

        .. sourcecode:: http

           POST /validate/check HTTP/1.1
           Host: example.com
           Accept: application/json

           user=user
           realm=realm1
           pass=s3cret123456

    **Example response** for a successful authentication:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "message": "matching 1 tokens",
                "serial": "PISP0000AB00",
                "type": "spass"
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": true
              },
              "version": "privacyIDEA unknown"
            }

    **Example response** for this first part of a challenge response
    authentication:

       .. sourcecode:: http

           HTTP/1.1 200 OK
           Content-Type: application/json

            {
              "detail": {
                "serial": "PIEM0000AB00",
                "type": "email",
                "transaction_id": "12345678901234567890",
                "multi_challenge: [ {"serial": "PIEM0000AB00",
                                     "transaction_id":  "12345678901234567890",
                                     "message": "Please enter otp from your
                                     email"},
                                    {"serial": "PISM12345678",
                                     "transaction_id": "12345678901234567890",
                                     "message": "Please enter otp from your
                                     SMS"}
                ]
              },
              "id": 1,
              "jsonrpc": "2.0",
              "result": {
                "status": true,
                "value": false
              },
              "version": "privacyIDEA unknown"
            }

    In this example two challenges are triggered, one with an email and one
    with an SMS. The application and thus the user has to decide, which one
    to use. They can use either.

    .. note:: All challenge response tokens have the same transaction_id in
       this case.
    """
    user = request.User
    serial = getParam(request.all_data, "serial")
    password = getParam(request.all_data, "pass", required)
    otp_only = getParam(request.all_data, "otponly")
    token_type = getParam(request.all_data, "type")
    options = {"g": g,
               "clientip": g.client_ip}
    # 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

    g.audit_object.log({"user": user.login,
                        "resolver": user.resolver,
                        "realm": user.realm})

    if serial:
        if user:
            # check if the given token belongs to the user
            if not get_tokens(user=user, serial=serial, count=True):
                raise ParameterError('Given serial does not belong to given user!')
        if not otp_only:
            result, details = check_serial_pass(serial, password, options=options)
        else:
            result, details = check_otp(serial, password)

    else:
        options["token_type"] = token_type
        result, details = check_user_pass(user, password, options=options)

    g.audit_object.log({"info": log_used_user(user, details.get("message")),
                        "success": result,
                        "serial": serial or details.get("serial"),
                        "token_type": details.get("type")})
    return send_result(result, details=details)