15.2.1.2.19. U2F Token¶
U2F is the “Universal 2nd Factor” specified by the FIDO Alliance. The register and authentication process is described here:
But you do not need to be aware of this. privacyIDEA wraps all FIDO specific communication, which should make it easier for you, to integrate the U2F tokens managed by privacyIDEA into your application.
U2F Tokens can be either
- registered by administrators for users or
- registered by the users themselves.
15.2.1.2.19.1. Enrollment¶
The enrollment/registering can be completely performed within privacyIDEA.
But if you want to enroll the U2F token via the REST API you need to do it in two steps:
15.2.1.2.19.1.1. 1. Step¶
POST /token/init HTTP/1.1
Host: example.com
Accept: application/json
type=utf
This step returns a serial number.
15.2.1.2.19.1.2. 2. Step¶
POST /token/init HTTP/1.1
Host: example.com
Accept: application/json
type=utf
serial=U2F1234578
clientdata=<clientdata>
regdata=<regdata>
clientdata and regdata are the values returned by the U2F device.
You need to call the javascript function
u2f.register([registerRequest], [], function(u2fData) {} );
and the responseHandler needs to send the clientdata and regdata back to privacyIDEA (2. step).
15.2.1.2.19.2. Authentication¶
The U2F token is a challenge response token. I.e. you need to trigger a challenge e.g. by sending the OTP PIN/Password for this token.
15.2.1.2.19.2.1. Get the challenge¶
POST /validate/check HTTP/1.1
Host: example.com
Accept: application/json
user=cornelius
pass=tokenpin
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"detail": {
"attributes": {
"hideResponseInput": true,
"img": ...imageUrl...
"u2fSignRequest": {
"challenge": "...",
"appId": "...",
"keyHandle": "...",
"version": "U2F_V2"
}
},
"message": "Please confirm with your U2F token (Yubico U2F EE ...)"
"transaction_id": "02235076952647019161"
},
"id": 1,
"jsonrpc": "2.0",
"result": {
"status": true,
"value": false,
},
"version": "privacyIDEA unknown"
}
15.2.1.2.19.2.2. Send the Response¶
The application now needs to call the javascript function u2f.sign with the u2fSignRequest from the response.
var signRequests = [ error.detail.attributes.u2fSignRequest ]; u2f.sign(signRequests, function(u2fResult) {} );
The response handler function needs to call the /validate/check API again with the signatureData and clientData returned by the U2F device in the u2fResult:
POST /validate/check HTTP/1.1
Host: example.com
Accept: application/json
user=cornelius
pass=
transaction_id=<transaction_id>
signaturedata=signatureData
clientdata=clientData
15.2.1.2.19.3. Implementation¶
-
class
privacyidea.lib.tokens.u2ftoken.
U2fTokenClass
(db_token)[source]¶ The U2F Token implementation.
-
static
api_endpoint
(request, g)[source]¶ This provides a function to be plugged into the API endpoint /ttype/u2f
The u2f token can return the facet list at this URL.
Parameters: - request – The Flask request
- g – The Flask global object g
Returns: Flask Response or text
-
check_otp
(otpval, counter=None, window=None, options=None)[source]¶ This checks the response of a previous challenge. :param otpval: N/A :param counter: The authentication counter :param window: N/A :param options: contains “clientdata”, “signaturedata” and
“transaction_id”Returns: A value > 0 in case of success
-
create_challenge
(transactionid=None, options=None)[source]¶ This method creates a challenge, which is submitted to the user. The submitted challenge will be preserved in the challenge database.
If no transaction id is given, the system will create a transaction id and return it, so that the response can refer to this transaction.
Parameters: - transactionid – the id of this challenge
- options (dict) – the request context parameters / data
Returns: tuple of (bool, message, transactionid, attributes)
Return type: tuple
The return tuple builds up like this:
bool
if submit was successful;message
which is displayed in the JSON response; additionalattributes
, which are displayed in the JSON response.
-
static
get_class_info
(key=None, ret='all')[source]¶ returns a subtree of the token definition
Parameters: - key (string) – subsection identifier
- ret (user defined) – default return value, if nothing is found
Returns: subsection if key exists or user defined
Return type: dict or scalar
-
static
get_class_prefix
()[source]¶ Return the prefix, that is used as a prefix for the serial numbers. :return: U2F :rtype: basestring
-
static
get_class_type
()[source]¶ Returns the internal token type identifier :return: u2f :rtype: basestring
-
get_init_detail
(params=None, user=None)[source]¶ At the end of the initialization we ask the user to press the button
-
is_challenge_request
(passw, user=None, options=None)[source]¶ check, if the request would start a challenge In fact every Request that is not a response needs to start a challenge request.
At the moment we do not think of other ways to trigger a challenge.
- This function is not decorated with
- @challenge_response_allowed
as the U2F token is always a challenge response token!
Parameters: - passw – The PIN of the token.
- options – dictionary of additional request parameters
Returns: returns true or false
-
static