We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Change yubico POST request to GET request
See: https://community.privacyidea.org/t/yubico-auth-not-working-since-a-few-hours-quickfix/977/3

We need to change the POST request to the yubicloud to a GET request.

*bummer*

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `privacyidea/lib/tokens/yubicotoken.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 #  privacyIDEA is a fork of LinOTP
4 #  May 08, 2014 Cornelius Kölbel
5 #  License:  AGPLv3
6 #  contact:  http://www.privacyidea.org
7 #
8 #  2017-11-24 Cornelius Kölbel <cornelius.koelbel@netknights.it>
9 #             Generate the nonce on an HSM
10 #  2016-04-04 Cornelius Kölbel <cornelius@privacyidea.org>
11 #             Use central yubico_api_signature function
12 #  2015-01-28 Rewrite during flask migration
13 #             Change to use requests module
14 #             Cornelius Kölbel <cornelius@privacyidea.org>
15 #
16 #
17 #  Copyright (C) 2010 - 2014 LSE Leading Security Experts GmbH
18 #  License:  LSE
19 #  contact:  http://www.linotp.org
20 #            http://www.lsexperts.de
21 #            linotp@lsexperts.de
22 #
23 # This code is free software; you can redistribute it and/or
24 # modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
25 # License as published by the Free Software Foundation; either
26 # version 3 of the License, or any later version.
27 #
28 # This code is distributed in the hope that it will be useful,
29 # but WITHOUT ANY WARRANTY; without even the implied warranty of
30 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31 # GNU AFFERO GENERAL PUBLIC LICENSE for more details.
32 #
33 # You should have received a copy of the GNU Affero General Public
34 # License along with this program.  If not, see <http://www.gnu.org/licenses/>.
35 #
36 __doc__ = """
37 This is the implementation of the yubico token type.
38 Authentication requests are forwarded to the Yubico Cloud service YubiCloud.
39 
40 The code is tested in tests/test_lib_tokens_yubico
41 """
42 import logging
43 from privacyidea.lib.decorators import check_token_locked
44 import traceback
45 import requests
46 from privacyidea.api.lib.utils import getParam
47 from privacyidea.lib.crypto import geturandom
48 from privacyidea.lib.config import get_from_config
49 from privacyidea.lib.log import log_with
50 from privacyidea.lib.tokenclass import TokenClass, TOKENKIND
51 from privacyidea.lib.tokens.yubikeytoken import (yubico_check_api_signature,
52                                                  yubico_api_signature)
53 import os
54 import binascii
55 from privacyidea.lib import _
56 
57 YUBICO_LEN_ID = 12
58 YUBICO_LEN_OTP = 44
59 YUBICO_URL = "https://api.yubico.com/wsapi/2.0/verify"
60 DEFAULT_CLIENT_ID = 20771
61 DEFAULT_API_KEY = "9iE9DRkPHQDJbAFFC31/dum5I54="
62 
63 optional = True
64 required = False
65 
66 log = logging.getLogger(__name__)
67 
68 
69 class YubicoTokenClass(TokenClass):
70 
71     def __init__(self, db_token):
72         TokenClass.__init__(self, db_token)
73         self.set_type(u"yubico")
74         self.tokenid = ""
75 
76     @staticmethod
77     def get_class_type():
78         return "yubico"
79 
80     @staticmethod
81     def get_class_prefix():
82         return "UBCM"
83 
84     @staticmethod
85     @log_with(log)
86     def get_class_info(key=None, ret='all'):
87         """
88         :param key: subsection identifier
89         :type key: string
90         :param ret: default return value, if nothing is found
91         :type ret: user defined
92         :return: subsection if key exists or user defined
93         :rtype: dict or string
94         """
95         res = {'type': 'yubico',
96                'title': 'Yubico Token',
97                'description': _('Yubikey Cloud mode: Forward authentication '
98                                 'request to YubiCloud.'),
99                'user':  ['enroll'],
100                # This tokentype is enrollable in the UI for...
101                'ui_enroll': ["admin", "user"],
102                'policy' : {},
103                }
104 
105         if key:
106             ret = res.get(key, {})
107         else:
108             if ret == 'all':
109                 ret = res
110         return ret
111 
112     def update(self, param):
113         tokenid = getParam(param, "yubico.tokenid", required)
114         if len(tokenid) < YUBICO_LEN_ID:
115             log.error("The tokenid needs to be {0:d} characters long!".format(YUBICO_LEN_ID))
116             raise Exception("The Yubikey token ID needs to be {0:d} characters long!".format(YUBICO_LEN_ID))
117 
118         if len(tokenid) > YUBICO_LEN_ID:
119             tokenid = tokenid[:YUBICO_LEN_ID]
120         self.tokenid = tokenid
121         # overwrite the maybe wrong lenght given at the command line
122         param['otplen'] = 44
123         TokenClass.update(self, param)
124         self.add_tokeninfo("yubico.tokenid", self.tokenid)
125         self.add_tokeninfo("tokenkind", TOKENKIND.HARDWARE)
126 
127     @log_with(log)
128     @check_token_locked
129     def check_otp(self, anOtpVal, counter=None, window=None, options=None):
130         """
131         Here we contact the Yubico Cloud server to validate the OtpVal.
132         """
133         res = -1
134 
135         apiId = get_from_config("yubico.id", DEFAULT_CLIENT_ID)
136         apiKey = get_from_config("yubico.secret", DEFAULT_API_KEY)
137         yubico_url = get_from_config("yubico.url", YUBICO_URL)
138 
139         if apiKey == DEFAULT_API_KEY or apiId == DEFAULT_CLIENT_ID:
140             log.warning("Usage of default apiKey or apiId not recommended!")
141             log.warning("Please register your own apiKey and apiId at "
142                         "yubico website!")
143             log.warning("Configure of apiKey and apiId at the "
144                         "privacyidea manage config menu!")
145 
146         tokenid = self.get_tokeninfo("yubico.tokenid")
147         if len(anOtpVal) < 12:
148             log.warning("The otpval is too short: {0!r}".format(anOtpVal))
149         elif anOtpVal[:12] != tokenid:
150             log.warning("The tokenid in the OTP value does not match "
151                         "the assigned token!")
152         else:
153             nonce = geturandom(20, hex=True)
154             p = {'nonce': nonce,
155                  'otp': anOtpVal,
156                  'id': apiId}
157             # Also send the signature to the yubico server
158             p["h"] = yubico_api_signature(p, apiKey)
159 
160             try:
161                 r = requests.post(yubico_url,
162                                   data=p)
163 
164                 if r.status_code == requests.codes.ok:
165                     response = r.text
166                     elements = response.split()
167                     data = {}
168                     for elem in elements:
169                         k, v = elem.split("=", 1)
170                         data[k] = v
171                     result = data.get("status")
172                     return_nonce = data.get("nonce")
173                     # check signature:
174                     signature_valid = yubico_check_api_signature(data, apiKey)
175 
176                     if not signature_valid:
177                         log.error("The hash of the return from the yubico "
178                                   "authentication server ({0!s}) "
179                                   "does not match the data!".format(yubico_url))
180 
181                     if nonce != return_nonce:
182                         log.error("The returned nonce does not match "
183                                   "the sent nonce!")
184 
185                     if result == "OK":
186                         res = 1
187                         if nonce != return_nonce or not signature_valid:
188                             log.warning("Nonce and Hash do not match.")
189                             res = -2
190                     else:
191                         # possible results are listed here:
192                         # https://github.com/Yubico/yubikey-val/wiki/ValidationProtocolV20
193                         log.warning("failed with {0!r}".format(result))
194 
195             except Exception as ex:
196                 log.error("Error getting response from Yubico Cloud Server"
197                           " (%r): %r" % (yubico_url, ex))
198                 log.debug("{0!s}".format(traceback.format_exc()))
199 
200         return res
201
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/privacyidea/lib/tokens/yubicotoken.py b/privacyidea/lib/tokens/yubicotoken.py
--- a/privacyidea/lib/tokens/yubicotoken.py
+++ b/privacyidea/lib/tokens/yubicotoken.py
@@ -5,6 +5,8 @@
 #  License:  AGPLv3
 #  contact:  http://www.privacyidea.org
 #
+#  2019-03-21 Cornelius Kölbel <cornelius.koelbel@netknights.it>
+#             Change POST to GET request
 #  2017-11-24 Cornelius Kölbel <cornelius.koelbel@netknights.it>
 #             Generate the nonce on an HSM
 #  2016-04-04 Cornelius Kölbel <cornelius@privacyidea.org>
@@ -50,13 +52,16 @@
 from privacyidea.lib.tokenclass import TokenClass, TOKENKIND
 from privacyidea.lib.tokens.yubikeytoken import (yubico_check_api_signature,
                                                  yubico_api_signature)
-import os
-import binascii
+from six.moves.urllib.parse import urlencode
 from privacyidea.lib import _
 
 YUBICO_LEN_ID = 12
 YUBICO_LEN_OTP = 44
 YUBICO_URL = "https://api.yubico.com/wsapi/2.0/verify"
+# The Yubico API requires GET requests. See: https://developers.yubico.com/yubikey-val/Validation_Protocol_V2.0.html
+# Previously we used POST requests.
+# If you want to have the old behaviour, you can set this to True
+DO_YUBICO_POST = False
 DEFAULT_CLIENT_ID = 20771
 DEFAULT_API_KEY = "9iE9DRkPHQDJbAFFC31/dum5I54="
 
@@ -135,6 +140,7 @@
         apiId = get_from_config("yubico.id", DEFAULT_CLIENT_ID)
         apiKey = get_from_config("yubico.secret", DEFAULT_API_KEY)
         yubico_url = get_from_config("yubico.url", YUBICO_URL)
+        do_yubico_post = get_from_config("yubico.do_post", DO_YUBICO_POST)
 
         if apiKey == DEFAULT_API_KEY or apiId == DEFAULT_CLIENT_ID:
             log.warning("Usage of default apiKey or apiId not recommended!")
@@ -158,8 +164,12 @@
             p["h"] = yubico_api_signature(p, apiKey)
 
             try:
-                r = requests.post(yubico_url,
-                                  data=p)
+                if do_yubico_post:
+                    r = requests.post(yubico_url,
+                                      data=p)
+                else:
+                    r = requests.get(yubico_url,
+                                     params=urlencode(p))
 
                 if r.status_code == requests.codes.ok:
                     response = r.text

{"golden_diff": "diff --git a/privacyidea/lib/tokens/yubicotoken.py b/privacyidea/lib/tokens/yubicotoken.py\n--- a/privacyidea/lib/tokens/yubicotoken.py\n+++ b/privacyidea/lib/tokens/yubicotoken.py\n@@ -5,6 +5,8 @@\n #  License:  AGPLv3\n #  contact:  http://www.privacyidea.org\n #\n+#  2019-03-21 Cornelius K\u00f6lbel <cornelius.koelbel@netknights.it>\n+#             Change POST to GET request\n #  2017-11-24 Cornelius K\u00f6lbel <cornelius.koelbel@netknights.it>\n #             Generate the nonce on an HSM\n #  2016-04-04 Cornelius K\u00f6lbel <cornelius@privacyidea.org>\n@@ -50,13 +52,16 @@\n from privacyidea.lib.tokenclass import TokenClass, TOKENKIND\n from privacyidea.lib.tokens.yubikeytoken import (yubico_check_api_signature,\n                                                  yubico_api_signature)\n-import os\n-import binascii\n+from six.moves.urllib.parse import urlencode\n from privacyidea.lib import _\n \n YUBICO_LEN_ID = 12\n YUBICO_LEN_OTP = 44\n YUBICO_URL = \"https://api.yubico.com/wsapi/2.0/verify\"\n+# The Yubico API requires GET requests. See: https://developers.yubico.com/yubikey-val/Validation_Protocol_V2.0.html\n+# Previously we used POST requests.\n+# If you want to have the old behaviour, you can set this to True\n+DO_YUBICO_POST = False\n DEFAULT_CLIENT_ID = 20771\n DEFAULT_API_KEY = \"9iE9DRkPHQDJbAFFC31/dum5I54=\"\n \n@@ -135,6 +140,7 @@\n         apiId = get_from_config(\"yubico.id\", DEFAULT_CLIENT_ID)\n         apiKey = get_from_config(\"yubico.secret\", DEFAULT_API_KEY)\n         yubico_url = get_from_config(\"yubico.url\", YUBICO_URL)\n+        do_yubico_post = get_from_config(\"yubico.do_post\", DO_YUBICO_POST)\n \n         if apiKey == DEFAULT_API_KEY or apiId == DEFAULT_CLIENT_ID:\n             log.warning(\"Usage of default apiKey or apiId not recommended!\")\n@@ -158,8 +164,12 @@\n             p[\"h\"] = yubico_api_signature(p, apiKey)\n \n             try:\n-                r = requests.post(yubico_url,\n-                                  data=p)\n+                if do_yubico_post:\n+                    r = requests.post(yubico_url,\n+                                      data=p)\n+                else:\n+                    r = requests.get(yubico_url,\n+                                     params=urlencode(p))\n \n                 if r.status_code == requests.codes.ok:\n                     response = r.text\n", "issue": "Change yubico POST request to GET request\nSee: https://community.privacyidea.org/t/yubico-auth-not-working-since-a-few-hours-quickfix/977/3\r\n\r\nWe need to change the POST request to the yubicloud to a GET request.\r\n\r\n*bummer*\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n#  privacyIDEA is a fork of LinOTP\n#  May 08, 2014 Cornelius K\u00f6lbel\n#  License:  AGPLv3\n#  contact:  http://www.privacyidea.org\n#\n#  2017-11-24 Cornelius K\u00f6lbel <cornelius.koelbel@netknights.it>\n#             Generate the nonce on an HSM\n#  2016-04-04 Cornelius K\u00f6lbel <cornelius@privacyidea.org>\n#             Use central yubico_api_signature function\n#  2015-01-28 Rewrite during flask migration\n#             Change to use requests module\n#             Cornelius K\u00f6lbel <cornelius@privacyidea.org>\n#\n#\n#  Copyright (C) 2010 - 2014 LSE Leading Security Experts GmbH\n#  License:  LSE\n#  contact:  http://www.linotp.org\n#            http://www.lsexperts.de\n#            linotp@lsexperts.de\n#\n# This code is free software; you can redistribute it and/or\n# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n# License as published by the Free Software Foundation; either\n# version 3 of the License, or any later version.\n#\n# This code is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU AFFERO GENERAL PUBLIC LICENSE for more details.\n#\n# You should have received a copy of the GNU Affero General Public\n# License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\n__doc__ = \"\"\"\nThis is the implementation of the yubico token type.\nAuthentication requests are forwarded to the Yubico Cloud service YubiCloud.\n\nThe code is tested in tests/test_lib_tokens_yubico\n\"\"\"\nimport logging\nfrom privacyidea.lib.decorators import check_token_locked\nimport traceback\nimport requests\nfrom privacyidea.api.lib.utils import getParam\nfrom privacyidea.lib.crypto import geturandom\nfrom privacyidea.lib.config import get_from_config\nfrom privacyidea.lib.log import log_with\nfrom privacyidea.lib.tokenclass import TokenClass, TOKENKIND\nfrom privacyidea.lib.tokens.yubikeytoken import (yubico_check_api_signature,\n                                                 yubico_api_signature)\nimport os\nimport binascii\nfrom privacyidea.lib import _\n\nYUBICO_LEN_ID = 12\nYUBICO_LEN_OTP = 44\nYUBICO_URL = \"https://api.yubico.com/wsapi/2.0/verify\"\nDEFAULT_CLIENT_ID = 20771\nDEFAULT_API_KEY = \"9iE9DRkPHQDJbAFFC31/dum5I54=\"\n\noptional = True\nrequired = False\n\nlog = logging.getLogger(__name__)\n\n\nclass YubicoTokenClass(TokenClass):\n\n    def __init__(self, db_token):\n        TokenClass.__init__(self, db_token)\n        self.set_type(u\"yubico\")\n        self.tokenid = \"\"\n\n    @staticmethod\n    def get_class_type():\n        return \"yubico\"\n\n    @staticmethod\n    def get_class_prefix():\n        return \"UBCM\"\n\n    @staticmethod\n    @log_with(log)\n    def get_class_info(key=None, ret='all'):\n        \"\"\"\n        :param key: subsection identifier\n        :type key: string\n        :param ret: default return value, if nothing is found\n        :type ret: user defined\n        :return: subsection if key exists or user defined\n        :rtype: dict or string\n        \"\"\"\n        res = {'type': 'yubico',\n               'title': 'Yubico Token',\n               'description': _('Yubikey Cloud mode: Forward authentication '\n                                'request to YubiCloud.'),\n               'user':  ['enroll'],\n               # This tokentype is enrollable in the UI for...\n               'ui_enroll': [\"admin\", \"user\"],\n               'policy' : {},\n               }\n\n        if key:\n            ret = res.get(key, {})\n        else:\n            if ret == 'all':\n                ret = res\n        return ret\n\n    def update(self, param):\n        tokenid = getParam(param, \"yubico.tokenid\", required)\n        if len(tokenid) < YUBICO_LEN_ID:\n            log.error(\"The tokenid needs to be {0:d} characters long!\".format(YUBICO_LEN_ID))\n            raise Exception(\"The Yubikey token ID needs to be {0:d} characters long!\".format(YUBICO_LEN_ID))\n\n        if len(tokenid) > YUBICO_LEN_ID:\n            tokenid = tokenid[:YUBICO_LEN_ID]\n        self.tokenid = tokenid\n        # overwrite the maybe wrong lenght given at the command line\n        param['otplen'] = 44\n        TokenClass.update(self, param)\n        self.add_tokeninfo(\"yubico.tokenid\", self.tokenid)\n        self.add_tokeninfo(\"tokenkind\", TOKENKIND.HARDWARE)\n\n    @log_with(log)\n    @check_token_locked\n    def check_otp(self, anOtpVal, counter=None, window=None, options=None):\n        \"\"\"\n        Here we contact the Yubico Cloud server to validate the OtpVal.\n        \"\"\"\n        res = -1\n\n        apiId = get_from_config(\"yubico.id\", DEFAULT_CLIENT_ID)\n        apiKey = get_from_config(\"yubico.secret\", DEFAULT_API_KEY)\n        yubico_url = get_from_config(\"yubico.url\", YUBICO_URL)\n\n        if apiKey == DEFAULT_API_KEY or apiId == DEFAULT_CLIENT_ID:\n            log.warning(\"Usage of default apiKey or apiId not recommended!\")\n            log.warning(\"Please register your own apiKey and apiId at \"\n                        \"yubico website!\")\n            log.warning(\"Configure of apiKey and apiId at the \"\n                        \"privacyidea manage config menu!\")\n\n        tokenid = self.get_tokeninfo(\"yubico.tokenid\")\n        if len(anOtpVal) < 12:\n            log.warning(\"The otpval is too short: {0!r}\".format(anOtpVal))\n        elif anOtpVal[:12] != tokenid:\n            log.warning(\"The tokenid in the OTP value does not match \"\n                        \"the assigned token!\")\n        else:\n            nonce = geturandom(20, hex=True)\n            p = {'nonce': nonce,\n                 'otp': anOtpVal,\n                 'id': apiId}\n            # Also send the signature to the yubico server\n            p[\"h\"] = yubico_api_signature(p, apiKey)\n\n            try:\n                r = requests.post(yubico_url,\n                                  data=p)\n\n                if r.status_code == requests.codes.ok:\n                    response = r.text\n                    elements = response.split()\n                    data = {}\n                    for elem in elements:\n                        k, v = elem.split(\"=\", 1)\n                        data[k] = v\n                    result = data.get(\"status\")\n                    return_nonce = data.get(\"nonce\")\n                    # check signature:\n                    signature_valid = yubico_check_api_signature(data, apiKey)\n\n                    if not signature_valid:\n                        log.error(\"The hash of the return from the yubico \"\n                                  \"authentication server ({0!s}) \"\n                                  \"does not match the data!\".format(yubico_url))\n\n                    if nonce != return_nonce:\n                        log.error(\"The returned nonce does not match \"\n                                  \"the sent nonce!\")\n\n                    if result == \"OK\":\n                        res = 1\n                        if nonce != return_nonce or not signature_valid:\n                            log.warning(\"Nonce and Hash do not match.\")\n                            res = -2\n                    else:\n                        # possible results are listed here:\n                        # https://github.com/Yubico/yubikey-val/wiki/ValidationProtocolV20\n                        log.warning(\"failed with {0!r}\".format(result))\n\n            except Exception as ex:\n                log.error(\"Error getting response from Yubico Cloud Server\"\n                          \" (%r): %r\" % (yubico_url, ex))\n                log.debug(\"{0!s}\".format(traceback.format_exc()))\n\n        return res\n", "path": "privacyidea/lib/tokens/yubicotoken.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n#  privacyIDEA is a fork of LinOTP\n#  May 08, 2014 Cornelius K\u00f6lbel\n#  License:  AGPLv3\n#  contact:  http://www.privacyidea.org\n#\n#  2019-03-21 Cornelius K\u00f6lbel <cornelius.koelbel@netknights.it>\n#             Change POST to GET request\n#  2017-11-24 Cornelius K\u00f6lbel <cornelius.koelbel@netknights.it>\n#             Generate the nonce on an HSM\n#  2016-04-04 Cornelius K\u00f6lbel <cornelius@privacyidea.org>\n#             Use central yubico_api_signature function\n#  2015-01-28 Rewrite during flask migration\n#             Change to use requests module\n#             Cornelius K\u00f6lbel <cornelius@privacyidea.org>\n#\n#\n#  Copyright (C) 2010 - 2014 LSE Leading Security Experts GmbH\n#  License:  LSE\n#  contact:  http://www.linotp.org\n#            http://www.lsexperts.de\n#            linotp@lsexperts.de\n#\n# This code is free software; you can redistribute it and/or\n# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n# License as published by the Free Software Foundation; either\n# version 3 of the License, or any later version.\n#\n# This code is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU AFFERO GENERAL PUBLIC LICENSE for more details.\n#\n# You should have received a copy of the GNU Affero General Public\n# License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\n__doc__ = \"\"\"\nThis is the implementation of the yubico token type.\nAuthentication requests are forwarded to the Yubico Cloud service YubiCloud.\n\nThe code is tested in tests/test_lib_tokens_yubico\n\"\"\"\nimport logging\nfrom privacyidea.lib.decorators import check_token_locked\nimport traceback\nimport requests\nfrom privacyidea.api.lib.utils import getParam\nfrom privacyidea.lib.crypto import geturandom\nfrom privacyidea.lib.config import get_from_config\nfrom privacyidea.lib.log import log_with\nfrom privacyidea.lib.tokenclass import TokenClass, TOKENKIND\nfrom privacyidea.lib.tokens.yubikeytoken import (yubico_check_api_signature,\n                                                 yubico_api_signature)\nfrom six.moves.urllib.parse import urlencode\nfrom privacyidea.lib import _\n\nYUBICO_LEN_ID = 12\nYUBICO_LEN_OTP = 44\nYUBICO_URL = \"https://api.yubico.com/wsapi/2.0/verify\"\n# The Yubico API requires GET requests. See: https://developers.yubico.com/yubikey-val/Validation_Protocol_V2.0.html\n# Previously we used POST requests.\n# If you want to have the old behaviour, you can set this to True\nDO_YUBICO_POST = False\nDEFAULT_CLIENT_ID = 20771\nDEFAULT_API_KEY = \"9iE9DRkPHQDJbAFFC31/dum5I54=\"\n\noptional = True\nrequired = False\n\nlog = logging.getLogger(__name__)\n\n\nclass YubicoTokenClass(TokenClass):\n\n    def __init__(self, db_token):\n        TokenClass.__init__(self, db_token)\n        self.set_type(u\"yubico\")\n        self.tokenid = \"\"\n\n    @staticmethod\n    def get_class_type():\n        return \"yubico\"\n\n    @staticmethod\n    def get_class_prefix():\n        return \"UBCM\"\n\n    @staticmethod\n    @log_with(log)\n    def get_class_info(key=None, ret='all'):\n        \"\"\"\n        :param key: subsection identifier\n        :type key: string\n        :param ret: default return value, if nothing is found\n        :type ret: user defined\n        :return: subsection if key exists or user defined\n        :rtype: dict or string\n        \"\"\"\n        res = {'type': 'yubico',\n               'title': 'Yubico Token',\n               'description': _('Yubikey Cloud mode: Forward authentication '\n                                'request to YubiCloud.'),\n               'user':  ['enroll'],\n               # This tokentype is enrollable in the UI for...\n               'ui_enroll': [\"admin\", \"user\"],\n               'policy' : {},\n               }\n\n        if key:\n            ret = res.get(key, {})\n        else:\n            if ret == 'all':\n                ret = res\n        return ret\n\n    def update(self, param):\n        tokenid = getParam(param, \"yubico.tokenid\", required)\n        if len(tokenid) < YUBICO_LEN_ID:\n            log.error(\"The tokenid needs to be {0:d} characters long!\".format(YUBICO_LEN_ID))\n            raise Exception(\"The Yubikey token ID needs to be {0:d} characters long!\".format(YUBICO_LEN_ID))\n\n        if len(tokenid) > YUBICO_LEN_ID:\n            tokenid = tokenid[:YUBICO_LEN_ID]\n        self.tokenid = tokenid\n        # overwrite the maybe wrong lenght given at the command line\n        param['otplen'] = 44\n        TokenClass.update(self, param)\n        self.add_tokeninfo(\"yubico.tokenid\", self.tokenid)\n        self.add_tokeninfo(\"tokenkind\", TOKENKIND.HARDWARE)\n\n    @log_with(log)\n    @check_token_locked\n    def check_otp(self, anOtpVal, counter=None, window=None, options=None):\n        \"\"\"\n        Here we contact the Yubico Cloud server to validate the OtpVal.\n        \"\"\"\n        res = -1\n\n        apiId = get_from_config(\"yubico.id\", DEFAULT_CLIENT_ID)\n        apiKey = get_from_config(\"yubico.secret\", DEFAULT_API_KEY)\n        yubico_url = get_from_config(\"yubico.url\", YUBICO_URL)\n        do_yubico_post = get_from_config(\"yubico.do_post\", DO_YUBICO_POST)\n\n        if apiKey == DEFAULT_API_KEY or apiId == DEFAULT_CLIENT_ID:\n            log.warning(\"Usage of default apiKey or apiId not recommended!\")\n            log.warning(\"Please register your own apiKey and apiId at \"\n                        \"yubico website!\")\n            log.warning(\"Configure of apiKey and apiId at the \"\n                        \"privacyidea manage config menu!\")\n\n        tokenid = self.get_tokeninfo(\"yubico.tokenid\")\n        if len(anOtpVal) < 12:\n            log.warning(\"The otpval is too short: {0!r}\".format(anOtpVal))\n        elif anOtpVal[:12] != tokenid:\n            log.warning(\"The tokenid in the OTP value does not match \"\n                        \"the assigned token!\")\n        else:\n            nonce = geturandom(20, hex=True)\n            p = {'nonce': nonce,\n                 'otp': anOtpVal,\n                 'id': apiId}\n            # Also send the signature to the yubico server\n            p[\"h\"] = yubico_api_signature(p, apiKey)\n\n            try:\n                if do_yubico_post:\n                    r = requests.post(yubico_url,\n                                      data=p)\n                else:\n                    r = requests.get(yubico_url,\n                                     params=urlencode(p))\n\n                if r.status_code == requests.codes.ok:\n                    response = r.text\n                    elements = response.split()\n                    data = {}\n                    for elem in elements:\n                        k, v = elem.split(\"=\", 1)\n                        data[k] = v\n                    result = data.get(\"status\")\n                    return_nonce = data.get(\"nonce\")\n                    # check signature:\n                    signature_valid = yubico_check_api_signature(data, apiKey)\n\n                    if not signature_valid:\n                        log.error(\"The hash of the return from the yubico \"\n                                  \"authentication server ({0!s}) \"\n                                  \"does not match the data!\".format(yubico_url))\n\n                    if nonce != return_nonce:\n                        log.error(\"The returned nonce does not match \"\n                                  \"the sent nonce!\")\n\n                    if result == \"OK\":\n                        res = 1\n                        if nonce != return_nonce or not signature_valid:\n                            log.warning(\"Nonce and Hash do not match.\")\n                            res = -2\n                    else:\n                        # possible results are listed here:\n                        # https://github.com/Yubico/yubikey-val/wiki/ValidationProtocolV20\n                        log.warning(\"failed with {0!r}\".format(result))\n\n            except Exception as ex:\n                log.error(\"Error getting response from Yubico Cloud Server\"\n                          \" (%r): %r\" % (yubico_url, ex))\n                log.debug(\"{0!s}\".format(traceback.format_exc()))\n\n        return res\n", "path": "privacyidea/lib/tokens/yubicotoken.py"}]}