def update(self, param, reset_failcount=True): ''' update - process the initialization parameters :param param: dict of initialization parameters :type param: dict :return: nothing ''' ## Remark: the otpKey is handled in the parent class val = getParam(param, "hashlib", optional) if val is not None: self.hashlibStr = val else: self.hashlibStr = 'sha1' ## check if the key_size id provided ## if not, we could derive it from the hashlib key_size = getParam(param, 'key_size', optional) if key_size == None: param['key_size'] = keylen.get(self.hashlibStr) param['hashlib'] = self.hashlibStr self.addToTokenInfo("hashlib", self.hashlibStr) TokenClass.update(self, param, reset_failcount) return
def update(self, param): # check for the required parameters ''' The key holds the public ssh key and this is required The key probably is of the form "ssh-rsa BASE64 comment" ''' if (self.hKeyRequired is True): getParam(param, "otpkey", required) key_elem = param.get("otpkey").split() if len(key_elem) != 3: raise Exception("The key must consist of 'ssh-rsa BASE64 comment'") key_type = key_elem[0] key = key_elem[1] key_comment = key_elem[2] # convert key to hex param["otpkey"] = binascii.hexlify(base64.b64decode(key)) self.addToTokenInfo("ssh_type", key_type) self.addToTokenInfo("ssh_comment", key_comment) # call the parents function TokenClass.update(self, param)
def test_99_delete_token(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.delete_token() db_token = Token.query.filter_by(serial=self.serial1).first() self.assertTrue(db_token is None, db_token)
def update(self, param): TokenClass.update(self, param) # The otplen is determined by the otpkey. So we # call the setOtpLen after the parents update, to overwrite # specified OTP lengths with the length of the password self.setOtpLen(0)
def revoke(self): """ This revokes the token. We need to determine the CA, which issues the certificate, contact the connector and revoke the certificate Some token types may revoke a token without locking it. """ TokenClass.revoke(self) # determine the CA and its connector. ti = self.get_tokeninfo() ca_specifier = ti.get("CA") log.debug("Revoking certificate {0!s} on CA {1!s}.".format( self.token.serial, ca_specifier)) certificate_pem = ti.get("certificate") # call CAConnector.revoke_cert() ca_obj = get_caconnector_object(ca_specifier) revoked = ca_obj.revoke_cert(certificate_pem) log.info("Certificate {0!s} revoked on CA {1!s}.".format(revoked, ca_specifier)) # call CAConnector.create_crl() crl = ca_obj.create_crl() log.info("CRL {0!s} created.".format(crl)) return revoked
def update(self, param, reset_failcount=True): """ This method is called during the initialization process. :param param: parameters from the token init :type param: dict :return: None """ TokenClass.update(self, param) description = "U2F initialization" reg_data = getParam(param, "regdata") if reg_data: self.init_step = 2 attestation_cert, user_pub_key, key_handle, \ signature, description = parse_registration_data(reg_data) client_data = getParam(param, "clientdata", required) client_data_str = url_decode(client_data) app_id = self.get_tokeninfo("appId", "") # Verify the registration data # In case of any crypto error, check_data raises an exception check_registration_data(attestation_cert, app_id, client_data_str, user_pub_key, key_handle, signature) self.set_otpkey(key_handle) self.add_tokeninfo("pubKey", user_pub_key) self.set_description(description)
def update(self, param): # New value radius_identifier = getParam(param, "radius.identifier") self.add_tokeninfo("radius.identifier", radius_identifier) # old values if not radius_identifier: radiusServer = getParam(param, "radius.server", optional=required) self.add_tokeninfo("radius.server", radiusServer) radius_secret = getParam(param, "radius.secret", optional=required) self.token.set_otpkey(binascii.hexlify(radius_secret)) system_settings = getParam(param, "radius.system_settings", default=False) self.add_tokeninfo("radius.system_settings", system_settings) if not radius_identifier and not (radiusServer or radius_secret) and \ not system_settings: raise ParameterError("Missing parameter: radius.identifier", id=905) # if another OTP length would be specified in /admin/init this would # be overwritten by the parent class, which is ok. self.set_otplen(6) TokenClass.update(self, param) val = getParam(param, "radius.local_checkpin", optional) or 0 self.add_tokeninfo("radius.local_checkpin", val) val = getParam(param, "radius.user", required) self.add_tokeninfo("radius.user", val)
def update(self, param, reset_failcount=True): """ update - process initialization parameters :param param: dict of initialization parameters :type param: dict :return: nothing """ if is_true(getParam(param, 'genkey', optional)): raise ParameterError("Generating OTP keys is not supported") upd_param = param.copy() # If the OTP key is given, it is given as a 496-character hex string which # encodes a 248-byte blob. As we want to set a 248-byte OTPKey (= Blob), # we unhexlify the OTP key if 'otpkey' in param: if len(param['otpkey']) != 496: raise ParameterError('Expected OTP key as 496-character hex string, but length is {!s}'.format( len(param['otpkey']) )) try: upd_param['otpkey'] = binascii.unhexlify(upd_param['otpkey']) except (binascii.Error, TypeError): raise ParameterError('Expected OTP key as 496-character hex string, but it is malformed') TokenClass.update(self, upd_param, reset_failcount)
def update(self, param): # check for the required parameters if (self.hKeyRequired is True): getParam(param, "otpkey", required) TokenClass.update(self, param)
def update(self, param): # cko: changed for backward compat getParam(param, "pin", optional) if not param.has_key('otpkey'): param['genkey'] = 1 TokenClass.update(self, param)
def update(self, param): """ This method is called during the initialization process. :param param: parameters from the token init :type param: dict :return: None """ TokenClass.update(self, param) request = getParam(param, "request", optional) spkac = getParam(param, "spkac", optional) certificate = None if request: ca = getParam(param, "ca", required) self.add_tokeninfo("CA", ca) # During the initialization process, we need to create the # certificate cacon = get_caconnector_object(ca) x509object = cacon.sign_request(request, options={"spkac": spkac}) certificate = crypto.dump_certificate(crypto.FILETYPE_PEM, x509object) else: certificate = getParam(param, "certificate", optional) if certificate: self.add_tokeninfo("certificate", certificate)
def test_10_get_hashlib(self): # check if functions are returned for hl in ["sha1", "md5", "sha256", "sha512", "sha224", "sha384", "", None]: self.assertTrue(hasattr(TokenClass.get_hashlib(hl), '__call__'), TokenClass.get_hashlib(hl))
def update(self, param): """ second phase of the init process - updates parameters :param param: the request parameters :return: - nothing - """ # if another OTP length would be specified in /admin/init this would # be overwritten by the parent class, which is ok. self.set_otplen(6) TokenClass.update(self, param) remoteServer = getParam(param, "remote.server", required) self.add_tokeninfo("remote.server", remoteServer) val = getParam(param, "remote.local_checkpin", optional) or 0 self.add_tokeninfo("remote.local_checkpin", val) for key in ["remote.serial", "remote.user", "remote.path", "remote.realm", "remote.resolver"]: val = getParam(param, key, optional) if val is not None: self.add_tokeninfo(key, val) self.add_tokeninfo("tokenkind", TOKENKIND.VIRTUAL)
def update(self, param): """ This method is called during the initialization process. :param param: parameters from the token init :type param: dict :return: None """ TokenClass.update(self, param) request = getParam(param, "request", optional) spkac = getParam(param, "spkac", optional) certificate = getParam(param, "certificate", optional) generate = getParam(param, "genkey", optional) if request or generate: # If we do not upload a user certificate, then we need a CA do # sign the uploaded request or generated certificate. ca = getParam(param, "ca", required) self.add_tokeninfo("CA", ca) cacon = get_caconnector_object(ca) if request: # During the initialization process, we need to create the # certificate x509object = cacon.sign_request(request, options={"spkac": spkac}) certificate = crypto.dump_certificate(crypto.FILETYPE_PEM, x509object) elif generate: # Create the certificate on behalf of another user. # Now we need to create the key pair, # the request # and the certificate # We need the user for whom the certificate should be created user = get_user_from_param(param, optionalOrRequired=required) keysize = getParam(param, "keysize", optional, 2048) key = crypto.PKey() key.generate_key(crypto.TYPE_RSA, keysize) req = crypto.X509Req() req.get_subject().CN = user.login # Add email to subject if user.info.get("email"): req.get_subject().emailAddress = user.info.get("email") req.get_subject().organizationalUnitName = user.realm # TODO: Add Country, Organization, Email # req.get_subject().countryName = 'xxx' # req.get_subject().stateOrProvinceName = 'xxx' # req.get_subject().localityName = 'xxx' # req.get_subject().organizationName = 'xxx' req.set_pubkey(key) req.sign(key, "sha256") x509object = cacon.sign_request(crypto.dump_certificate_request( crypto.FILETYPE_PEM, req)) certificate = crypto.dump_certificate(crypto.FILETYPE_PEM, x509object) # Save the private key to the encrypted key field of the token s = crypto.dump_privatekey(crypto.FILETYPE_PEM, key) self.add_tokeninfo("privatekey", s, value_type="password") if certificate: self.add_tokeninfo("certificate", certificate)
def update(self, param): self.radiusServer = getParam(param, "radius.server", required) # if another OTP length would be specified in /admin/init this would # be overwritten by the parent class, which is ok. self.setOtpLen(6) val = getParam(param, "radius.local_checkpin", optional) if val is not None: self.radiusLocal_checkpin = val val = getParam(param, "radius.user", required) if val is not None: self.radiusUser = val val = getParam(param, "radius.secret", required) if val is not None: self.radiusSecret = val if self.radiusSecret == VOID_RADIUS_SECRET: log.warning("Usage of default radius secret is not recomended!!") TokenClass.update(self, param) # We need to write the secret! self.token.setHKey(binascii.hexlify(self.radiusSecret)) self.addToTokenInfo("radius.server", self.radiusServer) self.addToTokenInfo("radius.local_checkpin", self.radiusLocal_checkpin) self.addToTokenInfo("radius.user", self.radiusUser)
def __init__(self, aToken): ''' constructor - create a token object :param aToken: instance of the orm db object :type aToken: orm object ''' TokenClass.__init__(self, aToken) self.setType(u"TOTP") self.hKeyRequired = True ''' timeStep defines the granularity: ''' self.timeStep = getFromConfig("totp.timeStep", 30) ''' window size in seconds: 30 seconds with as step width of 30 seconds results in a window of 1 which is one attempt ''' self.timeWindow = getFromConfig("totp.timeWindow", 180) '''the time shift is specified in seconds - and could be positive and negative ''' self.timeShift = getFromConfig("totp.timeShift", 0) '''we support various hashlib methods, but only on create which is effectively set in the update ''' self.hashlibStr = getFromConfig("totp.hashlib", u'sha1') return
def test_18_challenges(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) db_token.set_pin("test") # No challenge request req = token.is_challenge_request("test", User(login="******", realm=self.realm1)) self.assertFalse(req, req) # A challenge request req = token.is_challenge_request("test", User(login="******", realm=self.realm1), {"data": "a challenge"}) self.assertTrue(req, req) resp = token.is_challenge_response(User(login="******", realm=self.realm1), "test123456") self.assertFalse(resp, resp) resp = token.is_challenge_response(User(login="******", realm=self.realm1), "test123456", options={"transaction_id": "123456789"}) self.assertTrue(resp, resp) # test if challenge is valid C = Challenge("S123455", transaction_id="tid", challenge="Who are you?") C.save() self.assertTrue(C.is_valid())
def test_20_check_challenge_response(self): db_token = Token.query.filter_by(serial=self.serial1).first() db_token.set_pin("test") token = TokenClass(db_token) r = token.check_challenge_response(user=None, passw="123454") # check that challenge does not match self.assertTrue(r == -1) # create a challenge and match the transaction_id c = Challenge(self.serial1, transaction_id="mytransaction", challenge="Blah, what now?") # save challenge to the database c.save() r = token.check_challenge_response(user=None, passw="123454", options={"state": "mytransaction"}) # The challenge matches, but the OTP does not match! self.assertTrue(r == -1, r) # test the challenge janitor c1 = Challenge(self.serial1, transaction_id="t1", validitytime=0) c1.save() c2 = Challenge(self.serial1, transaction_id="t2", validitytime=0) c2.save() c3 = Challenge(self.serial1, transaction_id="t3", validitytime=0) c3.save() c4 = Challenge(self.serial1, transaction_id="t4", validitytime=0) c4.save() # Delete potentiall expired challenges token.challenge_janitor() # Check, that the challenge does not exist anymore r = Challenge.query.filter(Challenge.transaction_id == "t1").count() self.assertTrue(r == 0, r)
def update(self, param, reset_failcount=True): """ update - process initialization parameters :param param: dict of initialization parameters :type param: dict :return: nothing """ if self.hKeyRequired is True: genkey = is_true(getParam(param, "genkey", optional)) if not param.get('keysize'): param['keysize'] = 16 if genkey: otpKey = generate_otpkey(param['keysize']) del param['genkey'] else: # genkey not set: check otpkey is given # this will raise an exception if otpkey is not present otpKey = getParam(param, "otpkey", required) param['otpkey'] = otpKey # motp token specific mOTPPin = getParam(param, "motppin", required) self.token.set_user_pin(mOTPPin) TokenClass.update(self, param, reset_failcount) return
def test_07_enable(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.enable(False) self.assertTrue(token.token.active is False) token.enable() self.assertTrue(token.token.active)
def update(self, param): """ The key holds the public ssh key and this is required The key probably is of the form "ssh-rsa BASE64 comment" """ # We need to save the token, so that we can later add the tokeninfo # Otherwise we might not have created the DB entry, yet and we would # be missing the token.id self.token.save() getParam(param, "sshkey", required) key_elem = param.get("sshkey").split(" ", 2) if len(key_elem) != 3 or key_elem[0] != "ssh-rsa": raise Exception("The key must consist of 'ssh-rsa BASE64 comment'") key_type = key_elem[0] key = key_elem[1] key_comment = key_elem[2] # convert key to hex self.add_tokeninfo("ssh_key", key, value_type="password") self.add_tokeninfo("ssh_type", key_type) self.add_tokeninfo("ssh_comment", key_comment) # call the parents function TokenClass.update(self, param)
def test_03_reset_failcounter(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.token.failcount = 10 token.reset() self.assertTrue(token.token.failcount == 0, token.token.failcount)
def test_36_change_pin(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) # Set a pin change date that is already over. token.set_next_pin_change("-1d") # check that the pin needs to be changed r = token.is_pin_change() self.assertEqual(r, True)
def __init__(self, db_token): """ :param db_token: the token :type db_token: database token object """ TokenClass.__init__(self, db_token) self.set_type(u"4eyes") # We can not do challenge response self.mode = ['authenticate']
def test_21_get_token_data_as_dict(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token_data = token.get_as_dict() self.assertTrue("info" in token_data) self.assertTrue(token_data.get("user_id") == "1000") self.assertTrue(token_data.get("tokentype") == "newtype") self.assertTrue(token_data.get("count_window") == 52)
def test_31_revoke(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.revoke() self.assertTrue(token.is_revoked()) self.assertTrue(token.is_locked()) self.assertTrue(token.token.active is False) # A revoked token can not be enabled anymore self.assertRaises(Exception, token.enable)
def update(self, param, reset_failcount=True): """ process the initialization parameters Do we really always need an otpkey? the otpKey is handled in the parent class :param param: dict of initialization parameters :type param: dict :return: nothing """ # In case am Immutable MultiDict: upd_param = {} for k, v in param.items(): upd_param[k] = v # Special handling of 2-step enrollment if is_true(getParam(param, "2stepinit", optional)): # Use the 2step_serversize setting for the size of the server secret # (if it is set) if "2step_serversize" in upd_param: upd_param["keysize"] = int(getParam(upd_param, "2step_serversize", required)) # Add twostep settings to the tokeninfo for key, default in [ ("2step_difficulty", TWOSTEP_DEFAULT_DIFFICULTY), ("2step_clientsize", TWOSTEP_DEFAULT_CLIENTSIZE)]: self.add_tokeninfo(key, getParam(param, key, optional, default)) val = getParam(upd_param, "hashlib", optional) if val is not None: hashlibStr = val else: hashlibStr = self.hashlib # check if the key_size is provided # if not, we could derive it from the hashlib key_size = getParam(upd_param, 'key_size', optional) \ or getParam(upd_param, 'keysize', optional) if key_size is None: upd_param['keysize'] = keylen.get(hashlibStr) otpKey = getParam(upd_param, "otpkey", optional) genkey = is_true(getParam(upd_param, "genkey", optional)) if genkey and otpKey: # The Base TokenClass does not allow otpkey and genkey at the # same time del upd_param['otpkey'] upd_param['hashlib'] = hashlibStr # We first need to call the parent class. Since exceptions would be # raised here. TokenClass.update(self, upd_param, reset_failcount) self.add_tokeninfo("hashlib", hashlibStr) # check the tokenkind if self.token.serial.startswith("UB"): self.add_tokeninfo("tokenkind", TOKENKIND.HARDWARE)
def __init__(self, db_token): """ constructor - create a token class object with its db token binding :param aToken: the db bound token """ TokenClass.__init__(self, db_token) self.set_type(u"vasco") self.hKeyRequired = True
def __init__(self, db_token): """ constructor - create a token class object with it's db token binding :param aToken: the db bound token """ TokenClass.__init__(self, db_token) self.set_type(u"remote") self.mode = ['authenticate', 'challenge']
def test_05_get_set_realms(self): set_realm(self.realm2) db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) realms = token.get_realms() self.assertTrue(len(realms) == 1, realms) token.set_realms([self.realm1, self.realm2]) realms = token.get_realms() self.assertTrue(len(realms) == 2, realms)
def test_37_is_orphaned(self): resolver = "orphreso" realm = "orphrealm" rid = save_resolver({ "resolver": resolver, "type": "passwdresolver", "fileName": PWFILE }) self.assertTrue(rid > 0, rid) (added, failed) = set_realm(realm, [resolver]) self.assertTrue(len(failed) == 0) self.assertTrue(len(added) == 1) # Assign token to user "cornelius" "realm1", "resolver1" "uid=1000 db_token = Token("orphaned", tokentype="spass", userid=1000, resolver=resolver, realm=realm) db_token.save() token_obj = TokenClass(db_token) orph = token_obj.is_orphaned() self.assertFalse(orph) # clean up token token_obj.delete_token() # Assign a token to a user in a resolver. user_id does not exist db_token = Token("orphaned", tokentype="spass", userid=872812, resolver=resolver, realm=realm) db_token.save() token_obj = TokenClass(db_token) orph = token_obj.is_orphaned() self.assertTrue(orph) # clean up token token_obj.delete_token() # A token, which a resolver name, that does not exist anymore db_token = Token("orphaned", tokentype="spass", userid=1000, resolver=resolver, realm=realm) db_token.save() # delete the realm delete_realm(realm) # token is orphaned token_obj = TokenClass(db_token) orph = token_obj.is_orphaned() self.assertTrue(orph) # delete the resolver delete_resolver(resolver) # token is orphaned token_obj = TokenClass(db_token) orph = token_obj.is_orphaned() self.assertTrue(orph) # clean up token token_obj.delete_token()
def __init__(self, aToken): TokenClass.__init__(self, aToken) self.set_type(u"certificate") self.otp_len = 0
def get_init_detail(self, params=None, user=None): """ to complete the token initialization some additional details should be returned, which are displayed at the end of the token initialization. This is the e.g. the enrollment URL for a Google Authenticator. """ response_detail = TokenClass.get_init_detail(self, params, user) params = params or {} tokenlabel = params.get("tokenlabel", "<s>") tokenissuer = params.get("tokenissuer", "privacyIDEA") # If the init_details contain an OTP key the OTP key # should be displayed as an enrollment URL otpkey = self.init_details.get('otpkey') # Add rollout state the response response_detail['rollout_state'] = self.token.rollout_state # Add two-step initialization parameters to response and QR code extra_data = {} if is_true(params.get("2stepinit")): twostep_parameters = self._get_twostep_parameters() extra_data.update(twostep_parameters) response_detail.update(twostep_parameters) imageurl = params.get("appimageurl") if imageurl: extra_data.update({"image": imageurl}) force_app_pin = params.get('force_app_pin') if force_app_pin: extra_data.update({'pin': True}) if otpkey: tok_type = self.type.lower() if user is not None: try: key_bin = binascii.unhexlify(otpkey) # also strip the padding =, as it will get problems with the google app. value_b32_str = b32encode_and_unicode(key_bin).strip('=') response_detail["otpkey"]["value_b32"] = value_b32_str goo_url = cr_google(key=otpkey, user=user.login, realm=user.realm, tokentype=tok_type.lower(), serial=self.get_serial(), tokenlabel=tokenlabel, hash_algo=params.get( "hashlib", "sha1"), digits=params.get("otplen", 6), period=params.get("timeStep", 30), issuer=tokenissuer, user_obj=user, extra_data=extra_data) response_detail["googleurl"] = { "description": _("URL for google " "Authenticator"), "value": goo_url, "img": create_img(goo_url, width=250) } oath_url = cr_oath(otpkey=otpkey, user=user.login, realm=user.realm, type=tok_type, serial=self.get_serial(), tokenlabel=tokenlabel, extra_data=extra_data) response_detail["oathurl"] = { "description": _("URL for" " OATH " "token"), "value": oath_url, "img": create_img(oath_url, width=250) } except Exception as ex: # pragma: no cover log.error("{0!s}".format((traceback.format_exc()))) log.error( 'failed to set oath or google url: {0!r}'.format(ex)) return response_detail
def update(self, param, reset_failcount=True): """ process the initialization parameters We need to distinguish the first authentication step and the second authentication step. 1. step: ``param`` contains: - ``type`` - ``genkey`` 2. step: ``param`` contains: - ``serial`` - ``fbtoken`` - ``pubkey`` :param param: dict of initialization parameters :type param: dict :return: nothing """ upd_param = {} for k, v in param.items(): upd_param[k] = v if "serial" in upd_param and "fbtoken" in upd_param and "pubkey" in upd_param: # We are in step 2: if self.token.rollout_state != "clientwait": raise ParameterError( "Invalid state! The token you want to enroll is not in the state 'clientwait'." ) enrollment_credential = getParam(upd_param, "enrollment_credential", optional=False) if enrollment_credential != self.get_tokeninfo( "enrollment_credential"): raise ParameterError( "Invalid enrollment credential. You are not authorized to finalize this token." ) self.del_tokeninfo("enrollment_credential") self.token.rollout_state = "enrolled" self.token.active = True self.add_tokeninfo(PUBLIC_KEY_SMARTPHONE, upd_param.get("pubkey")) self.add_tokeninfo("firebase_token", upd_param.get("fbtoken")) # create a keypair for the server side. pub_key, priv_key = generate_keypair(4096) self.add_tokeninfo(PUBLIC_KEY_SERVER, pub_key) self.add_tokeninfo(PRIVATE_KEY_SERVER, priv_key, "password") elif "genkey" in upd_param: # We are in step 1: upd_param["2stepinit"] = 1 self.add_tokeninfo("enrollment_credential", geturandom(20, hex=True)) # We also store the firebase config, that was used during the enrollment. self.add_tokeninfo(PUSH_ACTION.FIREBASE_CONFIG, param.get(PUSH_ACTION.FIREBASE_CONFIG)) else: raise ParameterError( "Invalid Parameters. Either provide (genkey) or (serial, fbtoken, pubkey)." ) TokenClass.update(self, upd_param, reset_failcount)
def get_init_detail(self, params=None, user=None): """ This returns the init details during enrollment. In the 1st step the QR Code is returned. """ response_detail = TokenClass.get_init_detail(self, params, user) if "otpkey" in response_detail: del response_detail["otpkey"] params = params or {} user = user or User() tokenlabel = params.get("tokenlabel", "<s>") tokenissuer = params.get("tokenissuer", "privacyIDEA") sslverify = getParam(params, PUSH_ACTION.SSL_VERIFY, allowed_values=["0", "1"], default="1") # Add rollout state the response response_detail['rollout_state'] = self.token.rollout_state extra_data = { "enrollment_credential": self.get_tokeninfo("enrollment_credential") } imageurl = params.get("appimageurl") if imageurl: extra_data.update({"image": imageurl}) if self.token.rollout_state == "clientwait": # Get the values from the configured PUSH config fb_identifier = params.get(PUSH_ACTION.FIREBASE_CONFIG) firebase_configs = get_smsgateway(identifier=fb_identifier, gwtype=GWTYPE) if len(firebase_configs) != 1: raise ParameterError("Unknown Firebase configuration!") fb_options = firebase_configs[0].option_dict for k in [ FIREBASE_CONFIG.PROJECT_NUMBER, FIREBASE_CONFIG.PROJECT_ID, FIREBASE_CONFIG.APP_ID, FIREBASE_CONFIG.API_KEY, FIREBASE_CONFIG.APP_ID_IOS, FIREBASE_CONFIG.API_KEY_IOS ]: extra_data[k] = fb_options.get(k) # this allows to upgrade our crypto extra_data["v"] = 1 extra_data["serial"] = self.get_serial() extra_data["sslverify"] = sslverify # We display this during the first enrollment step! qr_url = create_push_token_url( url=fb_options.get(FIREBASE_CONFIG.REGISTRATION_URL), user=user.login, realm=user.realm, serial=self.get_serial(), tokenlabel=tokenlabel, issuer=tokenissuer, user_obj=user, extra_data=extra_data, ttl=fb_options.get(FIREBASE_CONFIG.TTL)) response_detail["pushurl"] = { "description": _("URL for privacyIDEA Push Token"), "value": qr_url, "img": create_img(qr_url, width=250) } self.add_tokeninfo(FIREBASE_CONFIG.PROJECT_ID, fb_options.get(FIREBASE_CONFIG.PROJECT_ID)) response_detail["enrollment_credential"] = self.get_tokeninfo( "enrollment_credential") elif self.token.rollout_state == "enrolled": # in the second enrollment step we return the public key of the server to the smartphone. pubkey = strip_key(self.get_tokeninfo(PUBLIC_KEY_SERVER)) response_detail["public_key"] = pubkey return response_detail
def test_40_failcounter_exceeded(self): from privacyidea.lib.tokenclass import (FAILCOUNTER_EXCEEDED, FAILCOUNTER_CLEAR_TIMEOUT) db_token = Token("failcounter", tokentype="spass") db_token.save() token_obj = TokenClass(db_token) for i in range(0, 11): token_obj.inc_failcount() now = datetime.datetime.now(tzlocal()).strftime(DATE_FORMAT) # Now the FAILCOUNTER_EXCEEDED is set ti = token_obj.get_tokeninfo(FAILCOUNTER_EXCEEDED) # We only compare the date self.assertEqual(ti[:10], now[:10]) # and the timezone self.assertEqual(ti[-5:], now[-5:]) # reset the failcounter token_obj.reset() ti = token_obj.get_tokeninfo(FAILCOUNTER_EXCEEDED) self.assertEqual(ti, None) # Now check with failcounter clear, with timeout 5 minutes set_privacyidea_config(FAILCOUNTER_CLEAR_TIMEOUT, 5) token_obj.set_failcount(10) failed_recently = (datetime.datetime.now(tzlocal()) - datetime.timedelta(minutes=3)).strftime(DATE_FORMAT) token_obj.add_tokeninfo(FAILCOUNTER_EXCEEDED, failed_recently) r = token_obj.check_reset_failcount() # the fail is only 3 minutes ago, so we will not reset and check will # be false self.assertFalse(r) # Set the timeout to a shorter value set_privacyidea_config(FAILCOUNTER_CLEAR_TIMEOUT, 2) r = token_obj.check_reset_failcount() # The fail is longer ago. self.assertTrue(r) # The tokeninfo of this token is deleted and the failcounter is 0 self.assertEqual(token_obj.get_tokeninfo(FAILCOUNTER_EXCEEDED), None) self.assertEqual(token_obj.get_failcount(), 0) token_obj.delete_token()
def test_15_check_pin(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.set_pin("test") self.assertTrue(token.check_pin("test")) self.assertFalse(token.check_pin("wrong pin"))
def __init__(self, db_token): TokenClass.__init__(self, db_token) self.set_type(u"sshkey")
def __init__(self, db_token): TokenClass.__init__(self, db_token) self.set_type(u"yubico") self.tokenid = ""
def update(self, param, reset_failcount=True): TokenClass.update(self, param, reset_failcount) self.add_tokeninfo("tokenkind", TOKENKIND.HARDWARE)
def __init__(self, db_token): TokenClass.__init__(self, db_token) self.set_type(u"yubikey") self.hKeyRequired = True
def __init__(self, aToken): TokenClass.__init__(self, aToken) self.hKeyRequired = True self.set_type(u"pw")
def test_34_get_default_settings(self): r = TokenClass.get_default_settings(FakeFlaskG(), {}) self.assertEqual(r, {})
def test_11_old_validity_time(self): old_time_1 = "11/04/17 22:00" # April 4th old_time_2 = "24/04/17 22:00" # April 24th db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.add_tokeninfo("validity_period_start", old_time_1) token.add_tokeninfo("validity_period_end", old_time_2) info = token.get_tokeninfo() self.assertEqual(info.get("validity_period_start"), old_time_1) self.assertEqual(info.get("validity_period_end"), old_time_2) e = token.get_validity_period_end() self.assertTrue(e.startswith("2017-04-24T22:00"), e) s = token.get_validity_period_start() self.assertTrue(s.startswith("2017-04-11T22:00"), s) # old date format has problems with check_validity_date start_date = datetime.datetime.now() - datetime.timedelta(days=15) end_date = datetime.datetime.now() + datetime.timedelta(days=15) start = start_date.strftime("%d/%m/%Y") end = end_date.strftime("%d/%m/%Y") # Need to write the old format to the database token.add_tokeninfo("validity_period_start", start) token.add_tokeninfo("validity_period_end", end) r = token.check_validity_period() self.assertTrue(r)
def __init__(self, aToken): TokenClass.__init__(self, aToken) self.set_type(u"indexedsecret") self.mode = ['challenge']
def test_38_last_auth(self): db_token = Token("lastauth001", tokentype="spass", userid=1000) db_token.save() token_obj = TokenClass(db_token) tdelta = datetime.timedelta(days=1) token_obj.add_tokeninfo(ACTION.LASTAUTH, datetime.datetime.now(tzlocal()) - tdelta) r = token_obj.check_last_auth_newer("10h") self.assertFalse(r) r = token_obj.check_last_auth_newer("2d") self.assertTrue(r) # Old time format # lastauth_alt = datetime.datetime.utcnow().isoformat() token_obj.add_tokeninfo(ACTION.LASTAUTH, datetime.datetime.utcnow() - tdelta) r = token_obj.check_last_auth_newer("10h") self.assertFalse(r) r = token_obj.check_last_auth_newer("2d") token_obj.delete_token()
def test_13_check_otp(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) self.assertTrue(token.check_otp_exist("123456") == -1)
def test_33_get_setting_type(self): r = TokenClass.get_setting_type("something") self.assertEqual(r, "")
def test_11_tokeninfo(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.add_tokeninfo("key1", "value2") info1 = token.get_tokeninfo() self.assertTrue("key1" in info1, info1) token.add_tokeninfo("key2", "value3") info2 = token.get_tokeninfo() self.assertTrue("key2" in info2, info2) token.set_tokeninfo(info1) info2 = token.get_tokeninfo() self.assertTrue("key2" not in info2, info2) self.assertTrue(token.get_tokeninfo("key1") == "value2", info2) # auth counter token.set_count_auth_success_max(200) token.set_count_auth_max(1000) token.set_count_auth_success(100) token.inc_count_auth_success() token.set_count_auth(200) token.inc_count_auth() self.assertTrue(token.get_count_auth_success_max() == 200) self.assertTrue(token.get_count_auth_success() == 101) self.assertTrue(token.get_count_auth_max() == 1000) self.assertTrue(token.get_count_auth() == 201) self.assertTrue(token.check_auth_counter()) token.set_count_auth_max(10) self.assertFalse(token.check_auth_counter()) token.set_count_auth_max(1000) token.set_count_auth_success_max(10) self.assertFalse(token.check_auth_counter()) # set the max counter to 0 means authentication is allowed # 0 is unlimited token.set_count_auth_max(0) token.set_count_auth_success_max(0) self.assertEqual(token.check_auth_counter(), True) # handle validity end date token.set_validity_period_end("2014-12-30T16:00+0400") end = token.get_validity_period_end() self.assertTrue(end == "2014-12-30T16:00+0400", end) self.assertRaises(TokenAdminError, token.set_validity_period_end, "wrong date") # handle validity start date token.set_validity_period_start("2014-12-30T16:00+0400") start = token.get_validity_period_start() self.assertTrue(start == "2014-12-30T16:00+0400", start) self.assertRaises(TokenAdminError, token.set_validity_period_start, "wrong date") self.assertFalse(token.check_validity_period()) # delete the validity period end by passing an empty string token.set_validity_period_end('') end = token.get_validity_period_end() self.assertTrue(end == "", end) self.assertTrue(token.check_validity_period()) # try the same for the validity period start start_date_5d = datetime.datetime.now( tzlocal()) + datetime.timedelta(5) token.set_validity_period_start(start_date_5d.strftime(DATE_FORMAT)) self.assertFalse(token.check_validity_period()) token.set_validity_period_start('') self.assertTrue(token.check_validity_period()) token.set_validity_period_end("2015-05-22T22:00:00.000Z") end = token.get_validity_period_end() self.assertEqual(end, "2015-05-22T22:00+0000") token.set_validity_period_start("2015-05-22T22:00:00.000Z") start = token.get_validity_period_start() self.assertEqual(start, "2015-05-22T22:00+0000") # check validity period # +5 days end_date = datetime.datetime.now(tzlocal()) + datetime.timedelta(5) end = end_date.strftime(DATE_FORMAT) token.set_validity_period_end(end) # - 5 days start_date = datetime.datetime.now(tzlocal()) - datetime.timedelta(5) start = start_date.strftime(DATE_FORMAT) token.set_validity_period_start(start) self.assertTrue(token.check_validity_period()) # check before start date # +5 days end_date = datetime.datetime.now(tzlocal()) + datetime.timedelta(5) end = end_date.strftime(DATE_FORMAT) token.set_validity_period_end(end) # + 2 days start_date = datetime.datetime.now(tzlocal()) + datetime.timedelta(2) start = start_date.strftime(DATE_FORMAT) token.set_validity_period_start(start) self.assertFalse(token.check_validity_period()) # check after enddate # -1 day end_date = datetime.datetime.now(tzlocal()) - datetime.timedelta(1) end = end_date.strftime(DATE_FORMAT) token.set_validity_period_end(end) # - 10 days start_date = datetime.datetime.now(tzlocal()) - datetime.timedelta(10) start = start_date.strftime(DATE_FORMAT) token.set_validity_period_start(start) self.assertFalse(token.check_validity_period())
def test_32_test_config(self): r = TokenClass.test_config() self.assertEqual(r[0], False) self.assertEqual(r[1], "Not implemented")
def test_04_base_methods(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) self.assertTrue(token.check_otp("123456", 1, 10) == -1) self.assertTrue(token.get_otp() == (-2, 0, 0, 0)) res = token.get_multi_otp() self.assertTrue(res[0] is False, res) c = token.create_challenge("transactionid") self.assertTrue(c[0], c) self.assertTrue("transactionid" in c[2], c) c = token.create_challenge() self.assertTrue(c[0], c) transaction_id = c[2] self.assertEqual(len(transaction_id), 20) # Now we create the challenge with the same transaction_id for # another token. db_token2 = Token(self.serial2, tokentype="spass") db_token2.save() token2 = TokenClass(db_token) c = token2.create_challenge(transaction_id) self.assertEqual(c[2], transaction_id) # Now there should be two entries with the same transaction_id r = Challenge.query.filter( Challenge.transaction_id == transaction_id).all() self.assertEqual(len(r), 2) # set the description token.set_description("something new") self.assertTrue(token.token.description == "something new", token.token) # set defaults token.set_defaults() self.assertTrue(token.token.otplen == 6) self.assertTrue(token.token.sync_window == 1000) token.resync("1234", "3456") token.token.count_window = 17 self.assertTrue(token.get_otp_count_window() == 17) token.token.count = 18 self.assertTrue(token.get_otp_count() == 18) token.token.active = False self.assertTrue(token.is_active() is False) token.token.failcount = 7 self.assertTrue(token.get_failcount() == 7) token.set_failcount(8) self.assertTrue(token.token.failcount == 8) token.token.maxfail = 12 self.assertTrue(token.get_max_failcount() == 12) self.assertTrue(token.get_user_id() == token.token.user_id) self.assertTrue(token.get_serial() == "SE123456", token.token.serial) self.assertTrue(token.get_tokentype() == "newtype", token.token.tokentype) token.set_so_pin("sopin") token.set_user_pin("userpin") token.set_otpkey("123456") token.set_otplen(8) token.set_otp_count(1000) self.assertTrue(len(token.token.so_pin) == 32, token.token.so_pin) self.assertTrue(len(token.token.user_pin) == 32, token.token.user_pin) self.assertTrue(len(token.token.key_enc) == 32, token.token.key_enc) self.assertTrue(token.get_otplen() == 8) self.assertTrue(token.token.count == 1000, token.token.count) token.set_maxfail(1000) self.assertTrue(token.token.maxfail == 1000) token.set_count_window(52) self.assertTrue(token.get_count_window() == 52) token.set_sync_window(53) self.assertTrue(token.get_sync_window() == 53)
def __init__(self, db_token): TokenClass.__init__(self, db_token) self.set_type(u"push") self.mode = ['challenge', 'authenticate'] self.hKeyRequired = False
def test_08_info(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.set_hashlib("sha1") tinfo = token.token.get_info() self.assertTrue("hashlib" in tinfo, tinfo)
def test_16_init_detail(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.add_init_details("otpkey", "secretkey") detail = token.get_init_detail() self.assertTrue("otpkey" in detail, detail) # but the otpkey must not be written to token.token.info (DB) self.assertTrue("otpkey" not in token.token.get_info(), token.token.get_info()) token.get_QRimage_data({"googleurl": "hotp://"}) self.assertRaises(Exception, token.set_init_details, "unvalid value") token.set_init_details({"detail1": "value1"}) self.assertTrue("detail1" in token.get_init_details(), token.get_init_details())
def test_09_failcount(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) start = token.token.failcount end = token.inc_failcount() self.assertTrue(end == start + 1, (end, start))
def update(self, param): """ This method is called during the initialization process. :param param: parameters from the token init :type param: dict :return: None """ TokenClass.update(self, param) request = getParam(param, "request", optional) spkac = getParam(param, "spkac", optional) certificate = getParam(param, "certificate", optional) generate = getParam(param, "genkey", optional) template_name = getParam(param, "template", optional) if request or generate: # If we do not upload a user certificate, then we need a CA do # sign the uploaded request or generated certificate. ca = getParam(param, "ca", required) self.add_tokeninfo("CA", ca) cacon = get_caconnector_object(ca) if request: # During the initialization process, we need to create the # certificate x509object = cacon.sign_request(request, options={ "spkac": spkac, "template": template_name }) certificate = crypto.dump_certificate(crypto.FILETYPE_PEM, x509object) elif generate: # Create the certificate on behalf of another user. # Now we need to create the key pair, # the request # and the certificate # We need the user for whom the certificate should be created user = get_user_from_param(param, optionalOrRequired=required) keysize = getParam(param, "keysize", optional, 2048) key = crypto.PKey() key.generate_key(crypto.TYPE_RSA, keysize) req = crypto.X509Req() req.get_subject().CN = user.login # Add email to subject if user.info.get("email"): req.get_subject().emailAddress = user.info.get("email") req.get_subject().organizationalUnitName = user.realm # TODO: Add Country, Organization, Email # req.get_subject().countryName = 'xxx' # req.get_subject().stateOrProvinceName = 'xxx' # req.get_subject().localityName = 'xxx' # req.get_subject().organizationName = 'xxx' req.set_pubkey(key) req.sign(key, "sha256") x509object = cacon.sign_request( crypto.dump_certificate_request(crypto.FILETYPE_PEM, req), options={"template": template_name}) certificate = crypto.dump_certificate(crypto.FILETYPE_PEM, x509object) # Save the private key to the encrypted key field of the token s = crypto.dump_privatekey(crypto.FILETYPE_PEM, key) self.add_tokeninfo("privatekey", s, value_type="password") if "pin" in param: self.set_pin(param.get("pin"), encrypt=True) if certificate: self.add_tokeninfo("certificate", certificate)
def test_15_status_validation(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.status_validation_fail() token.status_validation_success()
def test_42_has_further_challenge(self): db_token = Token("furhterchallenge", tokentype="spass") db_token.save() token_obj = TokenClass(db_token) self.assertFalse(token_obj.has_further_challenge()) token_obj.delete_token()
def test_35_next_pin_change(self): ndate = (datetime.datetime.now(tzlocal()) + datetime.timedelta(12)).strftime(DATE_FORMAT) db_token = Token.query.filter_by(serial=self.serial1).first() token = TokenClass(db_token) token.set_next_pin_change("12d") r = token.get_tokeninfo("next_pin_change") self.assertEqual(r, ndate) token.set_next_pin_change("12d", password=True) r = token.get_tokeninfo("next_password_change") self.assertEqual(r, ndate) # The password must not be changed r = token.is_pin_change(password=True) self.assertEqual(r, False) datestring = "03/04/01 10:00" token.add_tokeninfo("next_pin_change", datestring) r = token.is_pin_change() self.assertTrue(r)