6.1.1.3.2.30. linotp.lib.tokenclass module

This file containes the standard token definitions: - OCRATokenClass

It also contains the base class “TokenClass”, that you may use to define your own tokenclasses.

You can add your own Tokens by adding the modules comma seperated to the directive ‘linotpTokenModules’ in the linotp.ini file.

depends on several modules from linotp.lib but also in case of VascoTokenClass on linotp.lib.ImportOTP.vasco

class linotp.lib.tokenclass.OcraTokenClass(aToken)[source]

Bases: linotp.lib.tokenclass.TokenClass

OcraTokenClass implement an ocra compliant token

used from Config
OcraMaxChallenges - number of open challenges per token if None: 3 OcraChallengeTimeout - timeout definition like 1D, 2H or 3M if None: 1M OcraDefaultSuite - if none :’OCRA-1:HOTP-SHA256-8:C-QN08’ QrOcraDefaultSuite - if none :’OCRA-1:HOTP-SHA256-8:C-QA64’

algorithm Ocra Token Rollout: tow phases of rollout

  1. https://linotpserver/admin/init?

    type=ocra& genkey=1& sharedsecret=1& user=BENUTZERNAME& session=SESSIONKEY

    =>> “serial” : SERIENNUMMER, “sharedsecret” : DATAOBJECT, “app_import” : IMPORTURL - genSharedSecret - vom HSM oder urandom ? - app_import : + linotp://

    • ocrasuite ->> default aus dem config: (DefaultOcraSuite)
    • sharedsecret (Länge wie ???)
    • seriennummer
    • seriennummer: uuid
    • token wird angelegt ist aber nicht aktiv!!! (counter == 0)
  2. https://linotpserver/admin/init?

    type=ocra& genkey=1& activationcode=AKTIVIERUNGSCODE& user=BENUTZERNAME& message=MESSAGE& session=SESSIONKEY

    =>> “serial” : SERIENNUMMER, “nonce” : DATAOBJECT, “transactionid” : “TRANSAKTIONSID, “app_import” : IMPORTURL

    • nonce - von HSM oder random ?
    • pkcs5 - kdf2
    • es darf zur einer Zeit nur eine QR Token inaktiv (== im Ausrollzustand) sein !!!!! der Token wird über den User gefunden
    • seed = pdkdf2(nonce + activcode + shared secret)
    • challenge generiern - von urandom oder HSM
  3. check_t
    • counter ist > nach der ersten Transaktion
    • if counter >= 1: delete sharedsecret löschen
autosync(ocraSuite, passw, challenge)[source]

try to resync a token automaticaly, if a former and the current request failed

Parameters:
  • ocraSuite (ocra object) – the ocraSuite of the current Token
  • passw
challenge(data, session='', typ='raw', challenge=None)[source]

the challenge method is for creating an transaction / challenge object

remark: the transaction has a maximum lifetime and a reference to the OcraSuite token (serial)

Parameters:
  • data (string or None) – data, which is the base for the challenge or None
  • session (string) – session support for ocratokens
Returns:

challenge response containing the transcation id and the challenge for the ocrasuite

:rtype : tuple of (transId(string), challenge(string))

checkOtp(passw, counter, window, options=None)[source]

checkOtp - standard callback of linotp to verify the token

Parameters:
  • passw (string) – the passw / otp, which has to be checked
  • counter (int) – the start counter
  • window (int) – the window, in which the token is valid
  • options (dict) – options contains the transaction id, eg. if check_t checks one transaction this will support assynchreonous otp checks (when check_t is used)
Returns:

verification counter or -1

Return type:

int (-1)

classmethod classInit(param, user=None)[source]
classmethod getClassPrefix()[source]
classmethod getClassType()[source]

getClassType - return the token type shortname

Returns:‘ocra’
Return type:string
getInfo()[source]

getInfo - return the status of the token rollout

Returns:info of the ocra token state
Return type:dict
getInitDetail(params, user=None)[source]

to complete the token normalisation, the response of the initialiastion should be build by the token specific method, the getInitDetails

getOcraSuiteSuite()[source]

getQROcraSuiteSuite - return the QR Ocra Suite - if none, it will return the default

Returns:Ocrasuite of token
Return type:string
getQRImageData(response_detail)[source]
getQROcraSuiteSuite()[source]

getQROcraSuiteSuite - return the QR Ocra Suite - if none, it will return the default

Returns:QROcrasuite of token
Return type:string
getStatus(transactionId)[source]

getStatus - assembles the status of a transaction / challenge in a dict

{ “serial”: SERIENNUMMER1,
“transactionid”: TRANSACTIONID1, “received_tan”: true, “valid_tan”: true, “failcount”: 0

}

Parameters:transactionId (string) – the transaction / challenge id
Returns:status dict
Return type:dict
classmethod getTransaction(transId)[source]

getTransaction - lookup for the challenge object of the given id

Parameters:transId (string) – challenge identifier
Returns:the challenge data object
Return type:OcraChallenge
classmethod getTransactions4serial(serial, currentOnly=False)[source]

getTransactions4serial - give all challenges for a given token serial number

Parameters:
  • serial (string) – token serial identifier
  • currentOnly (boolean flag) – boolean Flag to return all Challenges (like for status request) or to return the eldest open transaction / challenge
Returns:

return a list of Challenges

Return type:

OcraChallenge obejct list

is_challenge_response(passw, user, options=None, challenges=None)[source]

check, if the request contains the result of a challenge

Parameters:
  • passw – password, which might be pin or pin+otp
  • user – the requesting user
  • options – dictionary of additional request parameters
Returns:

returns true or false

classmethod maxChallengeJanitor(transId=None, serial=None)[source]

maxChallengeJanitor - remove for one token (serial) all challengens but the last ones

Parameters:
  • transId (string) – the current transaction, which provides a the lookup for the serial number
  • serial (string) – the serial number of the token
Returns:

  • nothing

classmethod maxChallengeRequestJanitor()[source]

maxChallengeRequestJanitor - remove all transactions / challenges which have been made more than maxChallengeRequests

Returns:
  • nothing
resync(otp1, otp2, options=None)[source]
  • for the resync to work, we take the last two transactions and their challenges
  • for each challenge, we search forward the sync window length
signData(data)[source]

sign the received data with the secret key

Parameters:data – arbitrary string object
Returns:hexlified signature of the data
statusValidationFail()[source]

statusValidationFail - callback to enable a status change,

will be called if the token verification has failed

:return - nothing

statusValidationSuccess()[source]

statusValidationSuccess - callback to enable a status change,

remark: will be called if the token shas been succesfull verified

Returns:
  • nothing
classmethod timeoutJanitor()[source]

timeoutJanitor - remove all outdated transactions / challenges

Returns:
  • nothing
update(params, reset_failcount=True)[source]

update: add further defintion for token from param in case of init

class linotp.lib.tokenclass.TokenClass(token)[source]

Bases: object

addToInfo(key, value)[source]
addToSession(Session)[source]
addToTokenInfo(key, value)[source]
authenticate(passw, user, options=None)[source]

This is the method that verifies single shot authentication like they are done with push button tokens.

It is a high level interface to support as well other tokens, which do not have a pin and otp seperation - they could overwrite this method

remarks: we have to call the global methods (check_pin,++) as they take the pin policies into account

Parameters:
  • passw (string) – the passw which could be pin+otp
  • user (User object) – The authenticating user
  • options ((dict)) – dictionary of additional request parameters
Returns:

returns tuple true or false for the pin match, the otpcounter (int) and the reply (dict) that will be added as additional information in the JSON response of /validate/check.

challenge_janitor(matching_challenges, challenges)[source]

This is the default janitor for the challenges of a token.

The idea is to delete all challenges, which have an id lower than the matching one. Other janitors could be implemented on a token base and overwrite this behaviour.

Remarks: In later versions this will be the place to hook a dynamically loaded default token specific janitor.

Parameters:
  • matching_challenges (list) – the last matching challenge
  • challenges (list) – all current challenges
Returns:

list of all challenges, which should be deleted

checkOtp(anOtpVal1, counter, window, options=None)[source]

This checks the OTP value, AFTER the upper level did the checkPIN

return:
counter of the matching OTP value.
checkPin(pin, options=None)[source]

checkPin - test is the pin is matching

Parameters:
  • pin – the pin
  • options – additional optional parameters, which could be token specific
Returns:

boolean

checkResponse4Challenge(user, passw, options=None, challenges=None)[source]

This method verifies if the given passw matches any existing challenge of the token.

It then returns the new otp_counter of the token and the list of the matching challenges.

In case of success the otp_counter needs to be > 0. The matching_challenges is passed to the method challenge_janitor() to clean up challenges.

Parameters:
  • user (User object) – the requesting user
  • passw (string) – the password (pin+otp)
  • options (dict) – additional arguments from the request, which could be token specific
  • challenges (list) – A sorted list of valid challenges for this token.
Returns:

tuple of (otpcounter and the list of matching challenges)

check_auth_counter()[source]

This function checks the count_auth and the count_auth_success

check_otp_exist(otp, window=None)[source]

checks if the given OTP value is/are values of this very token. This is used to autoassign and to determine the serial number of a token.

check_validity_period()[source]

This checks if the datetime.datetime.now() is within the validity period of the token.

Returns either True/False

createChallenge(transactionid, options=None)[source]

This method creates a challenge, which is submitted to the user. The submitted challenge will be preserved in the challenge database.

This method is called after the method initChallenge().

Parameters:
  • transactionid – the id of this challenge
  • options (dict) – the request context parameters / data
Returns:

tuple of (bool, message, data, attributes)

The return tuple builds up like this:

bool if submit was successfull; message which is displayed in the JSON response; data is preserved in the challenge; additional attributes, which are displayed in the JSON response.

deleteToken()[source]
enable(enable)[source]
flush()[source]
classmethod getClassPrefix()[source]
classmethod getClassType()[source]
getCounterWindow()[source]
getFailCount()[source]
getFromTokenInfo(key, default=None)[source]
getHashlib(hLibStr)[source]
getInfo()[source]

getInfo - return the status of the token rollout

Returns:return the status dict.
Return type:dict
getInitDetail(params, user=None)[source]

to complete the token normalisation, the response of the initialiastion should be build by the token specific method, the getInitDetails

getMaxFailCount()[source]
getOtp(curtTime='')[source]

The default token does not support getting the otp value will return something like:

1, pin, otpval, combined

a negative value is a failure.

getOtpCount()[source]
getOtpCountWindow()[source]
getOtpLen()[source]
getPinHashSeed()[source]
getQRImageData(response_detail)[source]
getSerial()[source]
getSyncWindow()[source]
getTokenInfo()[source]
getType()[source]
getUser()[source]
getUserId()[source]
get_count_auth()[source]
get_count_auth_max()[source]
get_count_auth_success()[source]
get_count_auth_success_max()[source]
get_multi_otp(count=0, epoch_start=0, epoch_end=0, curTime=None)[source]

This returns a dictionary of multiple future OTP values of a token.

parameter
count - how many otp values should be returned epoch_start - time based tokens: start when epoch_end - time based tokens: stop when
return
True/False error text OTP dictionary
get_validity_period_end()[source]

returns the end of validity period (if set)

get_validity_period_start()[source]

returns the start of validity period (if set)

get_vars(save=False)[source]

return the token state as dicts :return: token as dict

incOtpCounter(counter, reset=True)[source]
method
incOtpCounter(aToken, counter)
parameters:
token - a token object counter - the new counter reset - optional -
exception:
in case of an transaction fail an exception is thrown
side effects:
default of reset will reset the failCounter
incOtpFailCounter()[source]
inc_count_auth()[source]
inc_count_auth_success()[source]
initChallenge(transactionid, challenges=None, options=None)[source]

This method initializes the challenge.

This is a hook that is called before the method createChallenge(), which will only be called if this method returns success==true.

Thus this method can be used, to verify if there is an outstanding challenge or if a new challenge needs to be created. E.g. this hook can be used, to implement a blocking mechanism to allow the creation of a new challenge only after a certain timeout. If there is an already outstanding challenge the return value can refer to this. (s. ticket #2986)

Parameters:
  • transactionid (string) – the id of the new challenge
  • options (dict) – the request parameters
  • challenges (list) – a list of all valid challenges for this token.
Returns:

tuple of ( success, transid, message, additional attributes )

The transid (the best transaction id for this request context), message, and additional attributes (dictionar) are displayed as results in the JSON response of the /validate/check request.

Only in case of success == true the next method createChallenge will be called.

isActive()[source]
is_challenge_request(passw, user, options=None)[source]

This method checks, if this is a request, that triggers a challenge.

The default behaviour to trigger a challenge is, if the passw parameter only contains the correct token pin and the request contains a data or a challenge key i.e. if the options parameter contains a key data or challenge.

Each token type can decide on its own under which condition a challenge is triggered by overwriting this method.

please note: in case of pin policy == 2 (no pin is required) the check_pin would always return true! Thus each request containing a data or challenge would trigger a challenge!

Parameters:
  • passw (string) – password, which might be pin or pin+otp
  • user (User object) – The user from the authentication request
  • options (dict) – dictionary of additional request parameters
Returns:

true or false

is_challenge_response(passw, user, options=None, challenges=None)[source]

This method checks, if this is a request, that is the response to a previously sent challenge.

The default behaviour to check if this is the response to a previous challenge is simply by checking if the request contains a parameter state or transactionid i.e. checking if the options parameter contains a key state or transactionid.

This method does not try to verify the response itself! It only determines, if this is a response for a challenge or not.

Parameters:
  • passw (string) – password, which might be pin or pin+otp
  • user (User object) – the requesting user
  • options ((dict)) – dictionary of additional request parameters
  • challenges – A list of challenges for this token. These challenges may be used, to identify if this request is a response for a challenge.
Returns:

true or false

is_challenge_valid(challenge=None)[source]

This method verifies if the given challenge is still valid.

The default implementation checks, if the challenge start is in the default validity time window.

Please note: This method does not check the response for the challenge itself. This is done by the method checkResponse4Challenge(). E.g. this very method is_challenge_valid is used by the method challenge_janitor() to clean up old challenges.

Parameters:challenge (challenge object) – The challenge to be checked
Returns:true or false
reset()[source]
resetTokenInfo()[source]
resync(otp1, otp2, options=None)[source]
setCounterWindow(countWindow)[source]
setDefaults()[source]
setDescription(description)[source]
setFailCount(failCount)[source]
setHashLib(hashlib)[source]
setInfo(info)[source]
setMaxFail(maxFail)[source]
setOtpCount(otpCount)[source]
setOtpKey(otpKey)[source]
setOtpLen(otplen)[source]
setPin(pin, param=None)[source]

set the PIN. The optional parameter “param” can hold the information, if the PIN is encrypted or hashed.

setPinHashSeed(pinhash, seed)[source]
setRealms(realms)[source]
setSoPin(soPin)[source]
setSyncWindow(syncWindow)[source]
setTokenInfo(info)[source]
setType(typ)[source]
setUid(uid, uidResolver, uidResClass)[source]

sets the UID values in the database

setUser(user, report)[source]
Parameters:
  • user – a User() object, consisting of loginname and realm
  • report – tbdf.
setUserPin(userPin)[source]
set_count_auth(count)[source]

Sets the counter for the occurred login attepms

set_count_auth_max(count)[source]

Sets the counter for the maximum allowed login attemps

set_count_auth_success(count)[source]

Sets the counter for the occurred successful logins

set_count_auth_success_max(count)[source]

Sets the counter for the maximum allowed successful logins

set_validity_period_end(end_date)[source]

sets the end date of the validity period for a token

set_validity_period_start(start_date)[source]

sets the start date of the validity period for a token

splitPinPass(passw)[source]
statusValidationFail()[source]
statusValidationSuccess()[source]
storeToken()[source]
update(param, reset_failcount=True)[source]