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') if otpkey: tok_type = self.type.lower() if user is not None: try: 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) 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) 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 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') if otpkey: tok_type = self.type.lower() if user is not None: try: 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) 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) 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 create_challenge(self, transactionid=None, options=None): """ 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. :param transactionid: the id of this challenge :param options: the request context parameters / data :type options: dict :return: tuple of (bool, message, transactionid, attributes) :rtype: tuple The return tuple builds up like this: ``bool`` if submit was successful; ``message`` which is displayed in the JSON response; additional ``attributes``, which are displayed in the JSON response. """ options = options or {} message = 'Please scan the QR Code' # Get ValidityTime=120s. Maybe there is a TIQRChallengeValidityTime... validity = int(get_from_config('DefaultChallengeValidityTime', 120)) tokentype = self.get_tokentype().lower() lookup_for = tokentype.capitalize() + 'ChallengeValidityTime' validity = int(get_from_config(lookup_for, validity)) # We need to set the user ID user_identifier, user_displayname = self.get_user_displayname() service_identifier = get_from_config("tiqr.serviceIdentifier") or \ "org.privacyidea" # Get the OCRASUITE from the token information ocrasuite = self.get_tokeninfo("ocrasuite") or OCRA_DEFAULT_SUITE # Depending on the OCRA-SUITE we create the challenge os = OCRASuite(ocrasuite) challenge = os.create_challenge() # Create the challenge in the database db_challenge = Challenge(self.token.serial, transaction_id=None, challenge=challenge, data=None, session=options.get("session"), validitytime=validity) db_challenge.save() authurl = "tiqrauth://%s@%s/%s/%s" % (user_identifier, service_identifier, db_challenge.transaction_id, challenge) attributes = {"img": create_img(authurl, width=250), "value": authurl, "poll": True, "hideResponseInput": True} return True, message, db_challenge.transaction_id, attributes
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_27_images(self): png_b64 = u'iVBORw0KGgoAAAANSUhEUgAAASIAAAEiAQAAAAB1xeIbAAABgElEQVR4nO2ZQ' \ u'Y6DMBAEaxbujpQH5CnwdPOglexjJKLeQ2xCsofdC4HA+IDAlERrGKx2Y+LvMX' \ u'z9AwKnnHLKKae2TlkZLZBbrM91pl9V1yGoTpKUwOx0M0UaSZKeqffrOgSVS49' \ u'LqZH1QPkMVtZ1KGq4jG9+4mGp9uXaoP1d/K2q3wcVJEVAsd6RNL5S79e1Z6r0' \ u'/WAANFiXzgA3W1fXEah77R/BgobL1SA8Rw1bVf/ZFHcr2aXmfpDSNKfxfqa4V' \ u'fWfTZU6E8Zi8mOQpNRI8TG3VfWfTc36XqrNTzdtq7z2y1G17wHFMH8Lkq85y1' \ u'Kz2peyP5Z/1eG1X4R69jkjRvhuNVyuJvKp3tiq+j1Qjxyz7K1y8f3Wr6pr39T' \ u'kJ6u7UYKZ7fE1Z3mq5phmJ1DMLYrcPL9/J6VII7oEkKclaH1dR6CsB6wPkvWU' \ u'JH8LuvZI1Qw5CMgg8hmRzyOEq7nPWZCa+3uY9rWpZsi+r12O+pVjwojKTOP/a' \ u'51yyimn9kL9ACOsApMnN2KuAAAAAElFTkSuQmCC' self.assertEquals(b64encode_and_unicode(create_png('Hallo')), png_b64) self.assertEquals(create_img('Hello', raw=True), u'data:image/png;base64,SGVsbG8=') self.assertEquals(create_img('Hallo'), u'data:image/png;base64,{0!s}'.format(png_b64))
def create_challenge(self, transactionid=None, options=None): """ 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. :param transactionid: the id of this challenge :param options: the request context parameters / data :type options: dict :return: tuple of (bool, message, transactionid, attributes) :rtype: tuple The return tuple builds up like this: ``bool`` if submit was successful; ``message`` which is displayed in the JSON response; additional ``attributes``, which are displayed in the JSON response. """ options = options or {} message = 'Please scan the QR Code' # Get ValidityTime=120s. Maybe there is a TIQRChallengeValidityTime... validity = int(get_from_config('DefaultChallengeValidityTime', 120)) tokentype = self.get_tokentype().lower() lookup_for = tokentype.capitalize() + 'ChallengeValidityTime' validity = int(get_from_config(lookup_for, validity)) # We need to set the user ID user_identifier, user_displayname = self.get_user_displayname() service_identifier = get_from_config("tiqr.serviceIdentifier") or \ "org.privacyidea" # Get the OCRASUITE from the token information ocrasuite = self.get_tokeninfo("ocrasuite") or OCRA_DEFAULT_SUITE # Depending on the OCRA-SUITE we create the challenge os = OCRASuite(ocrasuite) challenge = os.create_challenge() # Create the challenge in the database db_challenge = Challenge(self.token.serial, transaction_id=None, challenge=challenge, data=None, session=options.get("session"), validitytime=validity) db_challenge.save() authurl = "tiqrauth://{0!s}@{1!s}/{2!s}/{3!s}".format(user_identifier, service_identifier, db_challenge.transaction_id, challenge) attributes = {"img": create_img(authurl, width=250), "value": authurl, "poll": True, "hideResponseInput": True} return True, message, db_challenge.transaction_id, attributes
def get_init_detail(self, params=None, user=None): """ to complete the token normalisation, the response of the initialization should be build by the token specific method, the getInitDetails """ response_detail = TokenClass.get_init_detail(self, params, user) otpkey = self.init_details.get('otpkey') if otpkey: tok_type = self.type.lower() if user is not None: try: motp_url = create_motp_url(otpkey, user.login, user.realm, serial=self.get_serial()) response_detail["motpurl"] = {"description": _("URL for MOTP " "token"), "value": motp_url, "img": create_img(motp_url, width=250) } except Exception as ex: # pragma: no cover log.debug("{0!s}".format(traceback.format_exc())) log.error('failed to set motp url: {0!r}'.format(ex)) return response_detail
def get_init_detail(self, params=None, user=None): """ At the end of the initialization we return the URL for the TiQR App. """ response_detail = TokenClass.get_init_detail(self, params, user) params = params or {} enroll_url = get_from_config("tiqr.regServer") log.info("using tiqr.regServer for enrollment: %s" % enroll_url) serial = self.token.serial session = generate_otpkey() # save the session in the token self.add_tokeninfo("session", session) tiqrenroll = "tiqrenroll://%s?action=%s&session=%s&serial=%s" % ( enroll_url, API_ACTIONS.METADATA, session, serial) response_detail["tiqrenroll"] = { "description": _("URL for TiQR " "enrollment"), "value": tiqrenroll, "img": create_img(tiqrenroll, width=250) } return response_detail
def get_init_detail(self, params=None, user=None): """ At the end of the initialization we return the URL for the TiQR App. """ response_detail = TokenClass.get_init_detail(self, params, user) params = params or {} enroll_url = get_from_config("tiqr.regServer") log.info("using tiqr.regServer for enrollment: {0!s}".format(enroll_url)) serial = self.token.serial session = generate_otpkey() # save the session in the token self.add_tokeninfo("session", session) tiqrenroll = "tiqrenroll://{0!s}?action={1!s}&session={2!s}&serial={3!s}".format( enroll_url, API_ACTIONS.METADATA, session, serial) response_detail["tiqrenroll"] = {"description": _("URL for TiQR " "enrollment"), "value": tiqrenroll, "img": create_img(tiqrenroll, width=250)} return response_detail
def create_challenge(self, transactionid=None, options=None): """ 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. :param transactionid: the id of this challenge :param options: the request context parameters / data :type options: dict :return: tuple of (bool, message, transactionid, attributes) :rtype: tuple The return tuple builds up like this: ``bool`` if submit was successful; ``message`` which is displayed in the JSON response; additional ``attributes``, which are displayed in the JSON response. """ options = options or {} message = 'Please answer the challenge' attributes = {} # Get ValidityTime=120s. Maybe there is a OCRAChallengeValidityTime... validity = int(get_from_config('DefaultChallengeValidityTime', 120)) tokentype = self.get_tokentype().lower() lookup_for = tokentype.capitalize() + 'ChallengeValidityTime' validity = int(get_from_config(lookup_for, validity)) # Get the OCRASUITE from the token information ocrasuite = self.get_tokeninfo("ocrasuite") or OCRA_DEFAULT_SUITE challenge = options.get("challenge") # TODO: we could add an additional parameter to hash the challenge # cleartext -> sha1 if not challenge: # If no challenge is given in the Request, we create a random # challenge based on the OCRA-SUITE os = OCRASuite(ocrasuite) challenge = os.create_challenge() else: # Add a random challenge if options.get("addrandomchallenge"): challenge += get_alphanum_str(int(options.get( "addrandomchallenge"))) attributes["original_challenge"] = challenge attributes["qrcode"] = create_img(challenge) if options.get("hashchallenge", "").lower() == "sha256": challenge = binascii.hexlify(hashlib.sha256(challenge).digest()) elif options.get("hashchallenge", "").lower() == "sha512": challenge = binascii.hexlify(hashlib.sha512(challenge).digest()) elif options.get("hashchallenge"): challenge = binascii.hexlify(hashlib.sha1(challenge).digest()) # Create the challenge in the database db_challenge = Challenge(self.token.serial, transaction_id=None, challenge=challenge, data=None, session=None, validitytime=validity) db_challenge.save() attributes["challenge"] = challenge return True, message, db_challenge.transaction_id, attributes
def get_webui_settings(request, response): """ This decorator is used in the /auth API to add configuration information like the logout_time or the policy_template_url to the response. :param request: flask request object :param response: flask response object :return: the response """ content = response.json # check, if the authentication was successful, then we need to do nothing if content.get("result").get("status") is True: role = content.get("result").get("value").get("role") loginname = content.get("result").get("value").get("username") realm = content.get("result").get("value").get("realm") or get_default_realm() # At this point the logged in user is not necessarily a user object. It can # also be a local admin. logout_time_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.LOGOUTTIME, user=loginname, realm=realm).action_values(unique=True) timeout_action_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.TIMEOUT_ACTION, user=loginname, realm=realm).action_values(unique=True) token_page_size_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.TOKENPAGESIZE, user=loginname, realm=realm).action_values(unique=True) user_page_size_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.USERPAGESIZE, user=loginname, realm=realm).action_values(unique=True) token_wizard_2nd = bool(role == ROLE.USER and Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.TOKENWIZARD2ND, user=loginname, realm=realm).policies()) admin_dashboard = (role == ROLE.ADMIN and Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.ADMIN_DASHBOARD, user=loginname, realm=realm).any()) token_wizard = False dialog_no_token = False if role == ROLE.USER: user_obj = User(loginname, realm) user_token_num = get_tokens(user=user_obj, count=True) token_wizard_pol = Match.user(g, scope=SCOPE.WEBUI, action=ACTION.TOKENWIZARD, user_object=user_obj).any() # We also need to check, if the user has not tokens assigned. # If the user has no tokens, we run the wizard. If the user # already has tokens, we do not run the wizard. token_wizard = token_wizard_pol and (user_token_num == 0) dialog_no_token_pol = Match.user(g, scope=SCOPE.WEBUI, action=ACTION.DIALOG_NO_TOKEN, user_object=user_obj).any() dialog_no_token = dialog_no_token_pol and (user_token_num == 0) user_details_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.USERDETAILS, user=loginname, realm=realm).policies() search_on_enter = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SEARCH_ON_ENTER, user=loginname, realm=realm).policies() hide_welcome = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.HIDE_WELCOME, user=loginname, realm=realm).any() hide_buttons = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.HIDE_BUTTONS, user=loginname, realm=realm).any() default_tokentype_pol = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.DEFAULT_TOKENTYPE, user=loginname, realm=realm).action_values(unique=True) show_seed = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_SEED, user=loginname, realm=realm).any() show_node = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_NODE, realm=realm).any() qr_ios_authenticator = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_IOS_AUTHENTICATOR, user=loginname, realm=realm).any() qr_android_authenticator = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_ANDROID_AUTHENTICATOR, user=loginname, realm=realm).any() qr_custom_authenticator_url = Match.generic(g, scope=SCOPE.WEBUI, action=ACTION.SHOW_CUSTOM_AUTHENTICATOR, user=loginname, realm=realm).action_values(unique=True) qr_image_android = create_img(DEFAULT_ANDROID_APP_URL) if qr_android_authenticator else None qr_image_ios = create_img(DEFAULT_IOS_APP_URL) if qr_ios_authenticator else None qr_image_custom = create_img(list(qr_custom_authenticator_url)[0]) if qr_custom_authenticator_url else None token_page_size = DEFAULT_PAGE_SIZE user_page_size = DEFAULT_PAGE_SIZE default_tokentype = DEFAULT_TOKENTYPE if len(token_page_size_pol) == 1: token_page_size = int(list(token_page_size_pol)[0]) if len(user_page_size_pol) == 1: user_page_size = int(list(user_page_size_pol)[0]) if len(default_tokentype_pol) == 1: default_tokentype = list(default_tokentype_pol)[0] logout_time = DEFAULT_LOGOUT_TIME if len(logout_time_pol) == 1: logout_time = int(list(logout_time_pol)[0]) timeout_action = DEFAULT_TIMEOUT_ACTION if len(timeout_action_pol) == 1: timeout_action = list(timeout_action_pol)[0] policy_template_url_pol = Match.action_only(g, scope=SCOPE.WEBUI, action=ACTION.POLICYTEMPLATEURL).action_values(unique=True) policy_template_url = DEFAULT_POLICY_TEMPLATE_URL if len(policy_template_url_pol) == 1: policy_template_url = list(policy_template_url_pol)[0] indexed_preset_attribute = Match.realm(g, scope=SCOPE.WEBUI, action="indexedsecret_preset_attribute", realm=realm).action_values(unique=True) if len(indexed_preset_attribute) == 1: content["result"]["value"]["indexedsecret_preset_attribute"] = list(indexed_preset_attribute)[0] # This only works for users, because the value of the policy does not change while logged in. if role == ROLE.USER and \ Match.user(g, SCOPE.USER, "indexedsecret_force_attribute", user_obj).action_values(unique=False): content["result"]["value"]["indexedsecret_force_attribute"] = 1 content["result"]["value"]["logout_time"] = logout_time content["result"]["value"]["token_page_size"] = token_page_size content["result"]["value"]["user_page_size"] = user_page_size content["result"]["value"]["policy_template_url"] = policy_template_url content["result"]["value"]["default_tokentype"] = default_tokentype content["result"]["value"]["user_details"] = len(user_details_pol) > 0 content["result"]["value"]["token_wizard"] = token_wizard content["result"]["value"]["token_wizard_2nd"] = token_wizard_2nd content["result"]["value"]["admin_dashboard"] = admin_dashboard content["result"]["value"]["dialog_no_token"] = dialog_no_token content["result"]["value"]["search_on_enter"] = len(search_on_enter) > 0 content["result"]["value"]["timeout_action"] = timeout_action content["result"]["value"]["hide_welcome"] = hide_welcome content["result"]["value"]["hide_buttons"] = hide_buttons content["result"]["value"]["show_seed"] = show_seed content["result"]["value"]["show_node"] = get_privacyidea_node() if show_node else "" content["result"]["value"]["subscription_status"] = subscription_status() content["result"]["value"]["qr_image_android"] = qr_image_android content["result"]["value"]["qr_image_ios"] = qr_image_ios content["result"]["value"]["qr_image_custom"] = qr_image_custom response.set_data(json.dumps(content)) return response
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}) 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 = base64.b32encode(key_bin).strip('=') value_b32_str = "{0!s}".format(value_b32) 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 create_challenge(self, transactionid=None, options=None): """ 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. :param transactionid: the id of this challenge :param options: the request context parameters / data :type options: dict :return: tuple of (bool, message, transactionid, reply_dict) :rtype: tuple The return tuple builds up like this: ``bool`` if submit was successful; ``message`` which is displayed in the JSON response; additional challenge ``reply_dict``, which are displayed in the JSON challenges response. """ options = options or {} message = 'Please answer the challenge' attributes = {} # Get ValidityTime=120s. Maybe there is a OCRAChallengeValidityTime... validity = int(get_from_config('DefaultChallengeValidityTime', 120)) tokentype = self.get_tokentype().lower() lookup_for = tokentype.capitalize() + 'ChallengeValidityTime' validity = int(get_from_config(lookup_for, validity)) # Get the OCRASUITE from the token information ocrasuite = self.get_tokeninfo("ocrasuite") or OCRA_DEFAULT_SUITE challenge = options.get("challenge") # TODO: we could add an additional parameter to hash the challenge # cleartext -> sha1 if not challenge: # If no challenge is given in the Request, we create a random # challenge based on the OCRA-SUITE os = OCRASuite(ocrasuite) challenge = os.create_challenge() else: # Add a random challenge if options.get("addrandomchallenge"): challenge += get_alphanum_str( int(options.get("addrandomchallenge"))) attributes["original_challenge"] = challenge attributes["qrcode"] = create_img(challenge) if options.get("hashchallenge", "").lower() == "sha256": challenge = hexlify_and_unicode( hashlib.sha256(to_bytes(challenge)).digest()) elif options.get("hashchallenge", "").lower() == "sha512": challenge = hexlify_and_unicode( hashlib.sha512(to_bytes(challenge)).digest()) elif options.get("hashchallenge"): challenge = hexlify_and_unicode( hashlib.sha1(to_bytes(challenge)).digest()) # Create the challenge in the database db_challenge = Challenge(self.token.serial, transaction_id=None, challenge=challenge, data=None, session=None, validitytime=validity) db_challenge.save() attributes["challenge"] = challenge reply_dict = {"attributes": attributes} return True, message, db_challenge.transaction_id, reply_dict
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}) 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