def checkTokenList(self, tokenList, passw, user=User(), options=None): """ identify a matching token and test, if the token is valid, locked .. This function is called by checkSerialPass and checkUserPass to :param tokenList: list of identified tokens :param passw: the provided passw (mostly pin+otp) :param user: the identified use - as class object :param options: additional parameters, which are passed to the token :return: tuple of boolean and optional response """ reply = None # add the user to the options, so that every token could see the user if not options: options = {} options["user"] = user # if there has been one token in challenge mode, we only handle # challenges # if we got a validation against a sub_challenge, we extend this to # be a validation to all challenges of the transaction id import copy check_options = copy.deepcopy(options) state = check_options.get("state", check_options.get("transactionid", "")) if state and "." in state: transid = state.split(".")[0] if "state" in check_options: check_options["state"] = transid if "transactionid" in check_options: check_options["transactionid"] = transid # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # transaction id optimization - part 1: # # if we have a transaction id, we check only those tokens # that belong to this transaction id: challenges = [] transaction_serials = [] transid = check_options.get("state", check_options.get("transactionid", "")) # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- audit_entry = {} audit_entry["action_detail"] = "no token found!" challenge_tokens = [] pin_matching_tokens = [] invalid_tokens = [] valid_tokens = [] related_challenges = [] # we have to preserve the result / reponse for token counters validation_results = {} for token in tokenList: audit_entry["serial"] = token.getSerial() audit_entry["token_type"] = token.getType() # preselect: the token must be in the same realm as the user if user is not None: t_realms = token.token.getRealmNames() u_realm = user.realm if (len(t_realms) > 0 and len(u_realm) > 0 and u_realm.lower() not in t_realms): audit_entry[ "action_detail"] = "Realm mismatch for token and user" continue # check if the token is the list of supported tokens # if not skip to the next token in list typ = token.getType() if typ.lower() not in tokenclass_registry: log.error( "token typ %r not found in tokenclasses: %r", typ, list(tokenclass_registry.keys()), ) audit_entry["action_detail"] = "Unknown Token type" continue if not token.isActive(): audit_entry["action_detail"] = "Token inactive" continue if token.getFailCount() >= token.getMaxFailCount(): audit_entry["action_detail"] = "Failcounter exceeded" token.incOtpFailCounter() continue # ---------------------------------------------------------------------- -- # check for restricted path usage path = context["Path"].strip("/").partition("/")[0] token_path = token.getFromTokenInfo("scope", {}).get("path", []) if token_path and path not in token_path: continue # -------------------------------------------------------------- -- # token validity handling if token.is_not_yet_valid(): msg = "Authentication validity period mismatch!" audit_entry["action_detail"] = msg token.incOtpFailCounter() continue if not token.is_valid(): if token.has_exceeded_usage(): msg = "Authentication counter exceeded" elif token.has_exceeded_success(): msg = "Authentication sucess counter exceeded" elif token.is_expired(): msg = "Authentication validity period exceeded" else: raise Exception("Validity check failed without reason") audit_entry["action_detail"] = msg token.incOtpFailCounter() # what should happen with exceeding tokens t_realms = None if not user.login and not user.realm: t_realms = token.token.getRealmNames() if disable_on_authentication_exceed(user, realms=t_realms): token.enable(False) if delete_on_authentication_exceed(user, realms=t_realms): token.deleteToken() continue # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # gather all open challenges for this token if transid: _expired, challenges = Challenges.get_challenges( token=token, transid=transid, filter_open=True) else: # if there is no transaction id given we check all challenges # related to the given token _expired, challenges = Challenges.get_challenges( token=token, filter_open=True, options=check_options) # -------------------------------------------------------------- -- # finally we check the token try: (ret, reply) = token.check_token(passw, user, options=check_options, challenges=challenges) except Exception as exx: # in case of a failure during checking token, we log the error # and continue with the next one log.error("checking token %r failed: %r", token, exx) ret = -1 reply = "%r" % exx audit_entry[ "action_detail"] = "checking token %r failed: %r" % (token, exx) audit_entry["info"] = audit_entry.get("info", "") + "%r" % exx continue finally: validation_results[token.getSerial()] = (ret, reply) (cToken, pToken, iToken, vToken) = token.get_verification_result() related_challenges.extend(token.related_challenges) challenge_tokens.extend(cToken) pin_matching_tokens.extend(pToken) invalid_tokens.extend(iToken) valid_tokens.extend(vToken) valid_tokens = list(set(valid_tokens)) invalid_tokens = list(set(invalid_tokens)) pin_matching_tokens = list(set(pin_matching_tokens)) challenge_tokens = list(set(challenge_tokens)) # end of token verification loop matching_challenges = [] for token in valid_tokens: matching_challenges.extend(token.matching_challenges) matching_challenges = list(set(matching_challenges)) # if there are related / sub challenges, we have to call their janitor Challenges.handle_related_challenge(matching_challenges) # now we finalize the token validation result fh = FinishTokens( valid_tokens, challenge_tokens, pin_matching_tokens, invalid_tokens, validation_results, user, options, audit_entry=audit_entry, ) (res, reply) = fh.finish_checked_tokens() # ------------------------------------------------------------------ -- # add to all tokens the last accessed time stamp add_last_accessed_info( set(valid_tokens + pin_matching_tokens + challenge_tokens + invalid_tokens)) # add time stamp to all valid tokens add_last_verified_info(valid_tokens) # ------------------------------------------------------------------ -- # now we care for all involved tokens and their challenges for token in set(valid_tokens + pin_matching_tokens + challenge_tokens + invalid_tokens): expired, _valid = Challenges.get_challenges(token) if expired: Challenges.delete_challenges(None, expired) log.debug( "Number of valid tokens found (validTokenNum): %d", len(valid_tokens), ) return (res, reply)
def checkTokenList(self, tokenList, passw, user=User(), options=None): """ identify a matching token and test, if the token is valid, locked .. This function is called by checkSerialPass and checkUserPass to :param tokenList: list of identified tokens :param passw: the provided passw (mostly pin+otp) :param user: the identified use - as class object :param options: additional parameters, which are passed to the token :return: tuple of boolean and optional response """ reply = None # add the user to the options, so that every token could see the user if not options: options = {} options['user'] = user # if there has been one token in challenge mode, we only handle # challenges # if we got a validation against a sub_challenge, we extend this to # be a validation to all challenges of the transaction id import copy check_options = copy.deepcopy(options) state = check_options.get( 'state', check_options.get('transactionid', '')) if state and '.' in state: transid = state.split('.')[0] if 'state' in check_options: check_options['state'] = transid if 'transactionid' in check_options: check_options['transactionid'] = transid # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # transaction id optimization - part 1: # # if we have a transaction id, we check only those tokens # that belong to this transaction id: challenges = [] transaction_serials = [] transid = check_options.get('state', check_options.get('transactionid', '')) if transid: expired, challenges = Challenges.get_challenges(transid=transid, filter_open=True) for challenge in challenges: serial = challenge.tokenserial transaction_serials.append(serial) # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- audit_entry = {} audit_entry['action_detail'] = "no token found!" challenge_tokens = [] pin_matching_tokens = [] invalid_tokens = [] valid_tokens = [] related_challenges = [] # we have to preserve the result / reponse for token counters validation_results = {} for token in tokenList: # transaction id optimization - part 2: if transid: if token.getSerial() not in transaction_serials: continue audit_entry['serial'] = token.getSerial() audit_entry['token_type'] = token.getType() # preselect: the token must be in the same realm as the user if user is not None: t_realms = token.token.getRealmNames() u_realm = user.realm if (len(t_realms) > 0 and len(u_realm) > 0 and u_realm.lower() not in t_realms): audit_entry['action_detail'] = ("Realm mismatch for " "token and user") continue # check if the token is the list of supported tokens # if not skip to the next token in list typ = token.getType() if typ.lower() not in tokenclass_registry: log.error('token typ %r not found in tokenclasses: %r' % (typ, list(tokenclass_registry.keys()))) audit_entry['action_detail'] = "Unknown Token type" continue if not token.isActive(): audit_entry['action_detail'] = "Token inactive" continue if token.getFailCount() >= token.getMaxFailCount(): audit_entry['action_detail'] = "Failcounter exceeded" token.incOtpFailCounter() continue # ---------------------------------------------------------------------- -- # check for restricted path usage path = context['Path'].strip('/').partition('/')[0] token_path = token.getFromTokenInfo('scope', {}).get('path', []) if token_path and path not in token_path: continue # -------------------------------------------------------------- -- # token validity handling now = datetime.now() if (token.validity_period_start and now < token.validity_period_start): audit_entry['action_detail'] = ("Authentication validity " "period mismatch!") token.incOtpFailCounter() continue token_success_excceed = ( token.count_auth_success_max > 0 and token.count_auth_success >= token.count_auth_success_max) token_access_exceed = ( token.count_auth_max > 0 and token.count_auth >= token.count_auth_max) token_expiry = ( token.validity_period_end and now >= token.validity_period_end) if token_success_excceed or token_access_exceed or token_expiry: if token_access_exceed: msg = "Authentication counter exceeded" if token_success_excceed: msg = "Authentication sucess counter exceeded" if token_expiry: msg = "Authentication validity period exceeded!" audit_entry['action_detail'] = msg token.incOtpFailCounter() # what should happen with exceeding tokens t_realms = None if not user.login and not user.realm: t_realms = token.token.getRealmNames() if disable_on_authentication_exceed(user, realms=t_realms): token.enable(False) if delete_on_authentication_exceed(user, realms=t_realms): token.deleteToken() continue # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # start the token validation if not transid: # if there is no transaction id given we check all token # related challenges (_ex_challenges, challenges) = Challenges.get_challenges(token, options=check_options, filter_open=True) try: (ret, reply) = token.check_token( passw, user, options=check_options, challenges=challenges) except Exception as exx: # in case of a failure during checking token, we log the error # and continue with the next one log.exception("checking token %r failed: %r" % (token, exx)) ret = -1 reply = "%r" % exx audit_entry['action_detail'] = ("checking token %r " "failed: %r" % (token, exx)) audit_entry['info'] = audit_entry.get('info','') + "%r" % exx continue finally: validation_results[token.getSerial()] = (ret, reply) (cToken, pToken, iToken, vToken) = token.get_verification_result() related_challenges.extend(token.related_challenges) challenge_tokens.extend(cToken) pin_matching_tokens.extend(pToken) invalid_tokens.extend(iToken) valid_tokens.extend(vToken) valid_tokens = list(set(valid_tokens)) invalid_tokens = list(set(invalid_tokens)) pin_matching_tokens = list(set(pin_matching_tokens)) challenge_tokens = list(set(challenge_tokens)) # end of token verification loop matching_challenges = [] for token in valid_tokens: matching_challenges.extend(token.matching_challenges) matching_challenges = list(set(matching_challenges)) # if there are related / sub challenges, we have to call their janitor Challenges.handle_related_challenge(matching_challenges) # now we finalize the token validation result fh = FinishTokens(valid_tokens, challenge_tokens, pin_matching_tokens, invalid_tokens, validation_results, user, options, audit_entry=audit_entry) (res, reply) = fh.finish_checked_tokens() # ------------------------------------------------------------------ -- # add to all tokens the last accessed time stamp add_last_accessed_info(valid_tokens + pin_matching_tokens + challenge_tokens + invalid_tokens) # add time stamp to all valid tokens add_last_verified_info(valid_tokens) # ------------------------------------------------------------------ -- # now we care for all involved tokens and their challenges for token in (valid_tokens + pin_matching_tokens + challenge_tokens + invalid_tokens): expired, _valid = Challenges.get_challenges(token) if expired: Challenges.delete_challenges(None, expired) log.debug("Number of valid tokens found " "(validTokenNum): %d" % len(valid_tokens)) return (res, reply)
def checkTokenList(self, tokenList, passw, user=User(), options=None): """ identify a matching token and test, if the token is valid, locked .. This function is called by checkSerialPass and checkUserPass to :param tokenList: list of identified tokens :param passw: the provided passw (mostly pin+otp) :param user: the identified use - as class object :param options: additional parameters, which are passed to the token :return: tuple of boolean and optional response """ reply = None # add the user to the options, so that every token could see the user if not options: options = {} options['user'] = user # if there has been one token in challenge mode, we only handle # challenges # if we got a validation against a sub_challenge, we extend this to # be a validation to all challenges of the transaction id import copy check_options = copy.deepcopy(options) state = check_options.get( 'state', check_options.get('transactionid', '')) if state and '.' in state: transid = state.split('.')[0] if 'state' in check_options: check_options['state'] = transid if 'transactionid' in check_options: check_options['transactionid'] = transid # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # transaction id optimization - part 1: # # if we have a transaction id, we check only those tokens # that belong to this transaction id: challenges = [] transaction_serials = [] transid = check_options.get('state', check_options.get('transactionid', '')) if transid: expired, challenges = Challenges.get_challenges(transid=transid, filter_open=True) for challenge in challenges: serial = challenge.tokenserial transaction_serials.append(serial) # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- audit_entry = {} audit_entry['action_detail'] = "no token found!" challenge_tokens = [] pin_matching_tokens = [] invalid_tokens = [] valid_tokens = [] related_challenges = [] # we have to preserve the result / reponse for token counters validation_results = {} for token in tokenList: # transaction id optimization - part 2: if transid: if token.getSerial() not in transaction_serials: continue audit_entry['serial'] = token.getSerial() audit_entry['token_type'] = token.getType() # preselect: the token must be in the same realm as the user if user is not None: t_realms = token.token.getRealmNames() u_realm = user.realm if (len(t_realms) > 0 and len(u_realm) > 0 and u_realm.lower() not in t_realms): audit_entry['action_detail'] = ("Realm mismatch for " "token and user") continue # check if the token is the list of supported tokens # if not skip to the next token in list typ = token.getType() if typ.lower() not in tokenclass_registry: log.error('token typ %r not found in tokenclasses: %r' % (typ, tokenclass_registry.keys())) audit_entry['action_detail'] = "Unknown Token type" continue if not token.isActive(): audit_entry['action_detail'] = "Token inactive" continue if token.getFailCount() >= token.getMaxFailCount(): audit_entry['action_detail'] = "Failcounter exceeded" token.incOtpFailCounter() continue # ---------------------------------------------------------------------- -- # check for restricted path usage path = context['Path'].strip('/').partition('/')[0] token_path = token.getFromTokenInfo('scope', {}).get('path', []) if token_path and path not in token_path: continue # -------------------------------------------------------------- -- # token validity handling now = datetime.now() if (token.validity_period_start and now < token.validity_period_start): audit_entry['action_detail'] = ("Authentication validity " "period mismatch!") token.incOtpFailCounter() continue token_success_excceed = ( token.count_auth_success_max > 0 and token.count_auth_success >= token.count_auth_success_max) token_access_exceed = ( token.count_auth_max > 0 and token.count_auth >= token.count_auth_max) token_expiry = ( token.validity_period_end and now >= token.validity_period_end) if token_success_excceed or token_access_exceed or token_expiry: if token_access_exceed: msg = "Authentication counter exceeded" if token_success_excceed: msg = "Authentication sucess counter exceeded" if token_expiry: msg = "Authentication validity period exceeded!" audit_entry['action_detail'] = msg token.incOtpFailCounter() # what should happen with exceeding tokens t_realms = None if not user.login and not user.realm: t_realms = token.token.getRealmNames() if disable_on_authentication_exceed(user, realms=t_realms): token.enable(False) if delete_on_authentication_exceed(user, realms=t_realms): token.deleteToken() continue # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # start the token validation if not transid: # if there is no transaction id given we check all token # related challenges (_ex_challenges, challenges) = Challenges.get_challenges(token, options=check_options, filter_open=True) try: (ret, reply) = token.check_token( passw, user, options=check_options, challenges=challenges) except Exception as exx: # in case of a failure during checking token, we log the error # and continue with the next one log.exception("checking token %r failed: %r" % (token, exx)) ret = -1 reply = "%r" % exx audit_entry['action_detail'] = ("checking token %r " "failed: %r" % (token, exx)) audit_entry['info'] = audit_entry.get('info','') + "%r" % exx continue finally: validation_results[token.getSerial()] = (ret, reply) (cToken, pToken, iToken, vToken) = token.get_verification_result() related_challenges.extend(token.related_challenges) challenge_tokens.extend(cToken) pin_matching_tokens.extend(pToken) invalid_tokens.extend(iToken) valid_tokens.extend(vToken) # end of token verification loop matching_challenges = [] for token in valid_tokens: matching_challenges.extend(token.matching_challenges) # if there are related / sub challenges, we have to call their janitor Challenges.handle_related_challenge(matching_challenges) # now we finalize the token validation result fh = FinishTokens(valid_tokens, challenge_tokens, pin_matching_tokens, invalid_tokens, validation_results, user, options, audit_entry=audit_entry) (res, reply) = fh.finish_checked_tokens() # add to all tokens the last accessd time stamp add_last_accessed_info( [valid_tokens, pin_matching_tokens, challenge_tokens, valid_tokens]) # now we care for all involved tokens and their challenges for token in (valid_tokens + pin_matching_tokens + challenge_tokens + invalid_tokens): expired, _valid = Challenges.get_challenges(token) if expired: Challenges.delete_challenges(None, expired) log.debug("Number of valid tokens found " "(validTokenNum): %d" % len(valid_tokens)) return (res, reply)