def getActivationCode(self): ''' method: orcra/getActivationCode description: returns an valid example activcation code arguments: ./. returns: JSON with "activationcode": "JZXW4ZI=2A" ''' from linotp.lib.crypt import createActivationCode res = {} #description = 'ocra/getActivationCode' try: params = getLowerParams(request.params) log.debug("[getActivationCode]: %r" % params) checkPolicyPre('ocra', "activationcode") ac = str(params.get('activationcode')) activationCode = createActivationCode(acode=ac) res = {'activationcode': activationCode} Session.commit() return sendResult(response, res, 1) except PolicyException as pe: log.error("[getActivationCode] policy failed: %r" % pe) log.error("[getActivationCode] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe)) except Exception as exx: log.error("[getActivationCode] failed: %r" % exx) log.error("[getActivationCode] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(exx), 0) finally: Session.close() log.debug('[getActivationCode] done')
def getActivationCode(self): ''' method: ocra/getActivationCode description: returns an valid example activcation code arguments: ./. returns: JSON with "activationcode": "JZXW4ZI=2A" ''' from linotp.lib.crypt import createActivationCode res = {} #description = 'ocra/getActivationCode' try: params = getLowerParams(request.params) log.debug("[getActivationCode]: %r" % params) checkPolicyPre('ocra', "activationcode") ac = str(params.get('activationcode')) activationCode = createActivationCode(acode=ac) res = {'activationcode':activationCode} Session.commit() return sendResult(response, res, 1) except PolicyException as pe: log.error("[getActivationCode] policy failed: %r" % pe) log.error("[getActivationCode] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe)) except Exception as exx: log.error("[getActivationCode] failed: %r" % exx) log.error("[getActivationCode] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(exx), 0) finally: Session.close() log.debug('[getActivationCode] done')
def tokeninfo(self): """ this returns the contents of /admin/show?serial=xyz in a html format """ param = request.params try: serial = getParam(param, "serial", required) filterRealm = "" # check admin authorization res = checkPolicyPre("admin", "show", param) filterRealm = res["realms"] # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. pol = getAdminPolicies("show") if not pol["active"]: filterRealm = ["*"] log.info("[tokeninfo] admin >%s< may display the following realms: %s" % (res["admin"], filterRealm)) log.info("[tokeninfo] displaying tokens: serial: %s", serial) toks = TokenIterator(User("", "", ""), serial, filterRealm=filterRealm) ### now row by row lines = [] for tok in toks: lines.append(tok) if len(lines) > 0: c.tokeninfo = lines[0] else: c.tokeninfo = {} for k in c.tokeninfo: if "LinOtp.TokenInfo" == k: try: # Try to convert string to Dictionary c.tokeninfo["LinOtp.TokenInfo"] = json.loads(c.tokeninfo["LinOtp.TokenInfo"]) except: pass return render("/manage/tokeninfo.mako") except PolicyException as pe: log.error("[tokeninfo] Error during checking policies: %r" % pe) log.error("[tokeninfo] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[tokeninfo] failed! %r" % e) log.error("[tokeninfo] %s" % traceback.format_exc()) Session.rollback() return sendError(response, e) finally: Session.close() log.debug("[tokeninfo] done")
def tokeninfo(self): ''' this returns the contents of /admin/show?serial=xyz in an html format ''' param = self.request_params try: try: serial = param['serial'] except KeyError: raise ParameterError("Missing parameter: 'serial'") filterRealm = "" # check admin authorization res = checkPolicyPre('admin', 'show', param) # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. filterRealm = ["*"] if res['active'] and res['realms']: filterRealm = res['realms'] log.info("[tokeninfo] admin >%s< may display the following realms:" " %s" % (res['admin'], filterRealm)) log.info("[tokeninfo] displaying tokens: serial: %s", serial) toks = TokenIterator(User("", "", ""), serial, filterRealm=filterRealm) # now row by row lines = [] for tok in toks: lines.append(tok) if len(lines) > 0: c.tokeninfo = lines[0] else: c.tokeninfo = {} for k in c.tokeninfo: if "LinOtp.TokenInfo" == k: try: # Try to convert string to Dictionary c.tokeninfo['LinOtp.TokenInfo'] = json.loads( c.tokeninfo['LinOtp.TokenInfo']) except: pass return render('/manage/tokeninfo.mako').decode('utf-8') except PolicyException as pe: log.exception("[tokeninfo] Error during checking policies: %r" % pe) db.session.rollback() return sendError(response, str(pe), 1) except Exception as e: log.exception("[tokeninfo] failed! %r" % e) db.session.rollback() return sendError(response, e)
def tokeninfo(self): ''' this returns the contents of /admin/show?serial=xyz in a html format ''' param = request.params try: serial = getParam(param, 'serial', required) filterRealm = "" # check admin authorization res = checkPolicyPre('admin', 'show', param) filterRealm = res['realms'] # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. pol = getAdminPolicies("show") if not pol['active']: filterRealm = ["*"] log.info("[tokeninfo] admin >%s< may display the following realms: %s" % (res['admin'], filterRealm)) log.info("[tokeninfo] displaying tokens: serial: %s", serial) toks = TokenIterator(User("", "", ""), serial, filterRealm=filterRealm) ### now row by row lines = [] for tok in toks: lines.append(tok) if len(lines) > 0: c.tokeninfo = lines[0] else: c.tokeninfo = {} for k in c.tokeninfo: if "LinOtp.TokenInfo" == k: try: # Try to convert string to Dictionary c.tokeninfo['LinOtp.TokenInfo'] = json.loads(c.tokeninfo['LinOtp.TokenInfo']) except: pass return render('/manage/tokeninfo.mako') except PolicyException as pe: log.error("[tokeninfo] Error during checking policies: %r" % pe) log.error("[tokeninfo] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[tokeninfo] failed! %r" % e) log.error("[tokeninfo] %s" % traceback.format_exc()) Session.rollback() return sendError(response, e) finally: Session.close() log.debug('[tokeninfo] done')
def tokeninfo(self): ''' this returns the contents of /admin/show?serial=xyz in an html format ''' param = request.params try: serial = getParam(param, 'serial', required) filterRealm = "" # check admin authorization res = checkPolicyPre('admin', 'show', param) # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. filterRealm = ["*"] if res['active'] and res['realms']: filterRealm = res['realms'] log.info("[tokeninfo] admin >%s< may display the following realms:" " %s" % (res['admin'], filterRealm)) log.info("[tokeninfo] displaying tokens: serial: %s", serial) toks = TokenIterator(User("", "", ""), serial, filterRealm=filterRealm) # now row by row lines = [] for tok in toks: lines.append(tok) if len(lines) > 0: c.tokeninfo = lines[0] else: c.tokeninfo = {} for k in c.tokeninfo: if "LinOtp.TokenInfo" == k: try: # Try to convert string to Dictionary c.tokeninfo['LinOtp.TokenInfo'] = json.loads( c.tokeninfo['LinOtp.TokenInfo']) except: pass return render('/manage/tokeninfo.mako') except PolicyException as pe: log.exception("[tokeninfo] Error during checking policies: %r" % pe) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.exception("[tokeninfo] failed! %r" % e) Session.rollback() return sendError(response, e) finally: Session.close() log.debug('[tokeninfo] done')
def getActivationCode(self): """ method: ocra/getActivationCode description: returns an valid example activcation code arguments: ./. returns: JSON with "activationcode": "JZXW4ZI=2A" """ from linotp.lib.crypt import createActivationCode res = {} # description = 'ocra/getActivationCode' try: params = getLowerParams(request.params) log.debug("[getActivationCode]: %r" % params) checkPolicyPre("ocra", "activationcode", context=self.request_context) ac = str(params.get("activationcode")) activationCode = createActivationCode(acode=ac) res = {"activationcode": activationCode} Session.commit() return sendResult(response, res, 1) except PolicyException as pe: log.exception("[getActivationCode] policy failed: %r" % pe) Session.rollback() return sendError(response, unicode(pe)) except Exception as exx: log.exception("[getActivationCode] failed: %r" % exx) Session.rollback() return sendError(response, unicode(exx), 0) finally: Session.close() log.debug("[getActivationCode] done")
def getAdminRealms(username): results = [] if username is None: return results from linotp.lib.policy import checkPolicyPre try: res = checkPolicyPre('admin', 'show', {}, user = User(username, '', "")) results = res['realms'] finally: pass return results
def getAdminRealms(username): results = [] if username is None: return results from linotp.lib.policy import checkPolicyPre try: res = checkPolicyPre("admin", "show", {}, user=User(username, "", "")) results = res["realms"] finally: pass return results
def users(self): ''' This function is used to fill the flexigrid. Unlike the complex /admin/userlist function, it only returns a simple array of the tokens. ''' param = self.request_params try: page = param.get("page", 1) qfilter = param.get("query", '*') or '*' qtype = param.get("qtype", 'username') sort = param.get("sortname", 'username') direction = param.get("sortorder", 'asc') psize = param.get("rp", 20) user = getUserFromParam(param) realms = get_realms_from_params( param, getAdminPolicies('userlist', scope='admin')) uniqueUsers = {} for realm in realms: # ---------------------------------------------------------- -- # check admin authorization: checkPolicyPre('admin',... # admin policies are special as they are acl which define # - for user (policy entry) # - the actions (policy entry) # - in the realm (policy entry) # is allowed. while the user.login is not evaluated, the # user.realm is. # # the admin policies are acls and are defined in contradiction # to the other policy scopes where actions are either defiend # for user or realm!! # so we have to check for every user.realm if isinstance(user, User): user.realm = realm checkPolicyPre('admin', 'userlist', param=param, user=user) users_list = getUserList( {qtype: qfilter, 'realm': realm}, user) # now create a unique list of users with the unique key of # userid + useridresolver for u in users_list: pkey = u['userid'] + ':' + u['useridresolver'] user_realms = uniqueUsers.get(pkey, {}).get('realms', []) user_realms.append(realm) u['realms'] = user_realms uniqueUsers[pkey] = u userNum = len(uniqueUsers) lines = [] for u in uniqueUsers.values(): # shorten the useridresolver, to get a better display value resolver_display = "" if "useridresolver" in u: if len(u['useridresolver'].split(".")) > 3: resolver_display = u['useridresolver'].split( ".")[3] + " (" + u['useridresolver'].split(".")[1] + ")" else: resolver_display = u['useridresolver'] lines.append( {'id': u['username'], 'cell': [ (u['username']) if u.has_key('username') else (""), (resolver_display), (u['surname']) if u.has_key('surname') else (""), (u['givenname']) if u.has_key( 'givenname') else (""), (u['email']) if u.has_key('email') else (""), (u['mobile']) if u.has_key('mobile') else (""), (u['phone']) if u.has_key('phone') else (""), (u['userid']) if u.has_key('userid') else (""), (u['realms']), ] } ) # sorting reverse = False sortnames = { 'username': 0, 'useridresolver': 1, 'surname': 2, 'givenname': 3, 'email': 4, 'mobile': 5, 'phone': 6, 'userid': 7 } if direction == "desc": reverse = True lines = sorted(lines, key=lambda user: user['cell'][sortnames[sort]], reverse=reverse, cmp=unicode_compare) # end: sorting # reducing the page if page and psize: page = int(page) psize = int(psize) start = psize * (page - 1) end = start + psize lines = lines[start:end] # We need to return 'page', 'total', 'rows' res = { "page": int(page), "total": userNum, "rows": lines } c.audit['success'] = True Session.commit() return sendResult(response, res) except PolicyException as pe: log.exception( "[userview_flexi] Error during checking policies: %r" % pe) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.exception("[userview_flexi] failed: %r" % e) Session.rollback() return sendError(response, e) finally: Session.close()
def getotp(self): ''' This function is used to retrieve the current otp value for a given user or a given serial If the user has more than one token, the list of the tokens is returend. method: gettoken/getotp arguments: user - username / loginname realm - additional realm to match the user to a useridresolver serial - the serial number of the token curTime - used ONY for internal testing: datetime.datetime object returns: JSON response ''' getotp_active = config.get("linotpGetotp.active") if "True" != getotp_active: return sendError(response, "getotp is not activated.", 0) param = request.params ret = {} res = -1 otpval = "" passw = "" serials = [] try: serial = getParam(param, "serial", optional) user = getUserFromParam(param, optional) curTime = getParam(param, "curTime", optional) c.audit['user'] = user.login if "" != user.login: c.audit['realm'] = user.realm or getDefaultRealm() if serial: log.debug("[getotp] retrieving OTP value for token %s" % serial) elif user.login: log.debug( "[getotp] retrieving OTP value for token for user %s@%s" % (user.login, user.realm)) toks = getTokens4UserOrSerial(user, serial) tokennum = len(toks) if tokennum > 1: log.debug( "[getotp] The user has more than one token. Returning the list of serials" ) res = -3 for token in toks: serials.append(token.getSerial()) elif 1 == tokennum: serial = toks[0].getSerial() log.debug( "[getotp] retrieving OTP for token %s for user %s@%s" % (serial, user.login, user.realm)) else: log.debug("[getotp] no token found for user %s@%s" % (user.login, user.realm)) res = -4 else: res = -5 # if a serial was given or a unique serial could be received from the given user. if serial: max_count = checkPolicyPre('gettoken', 'max_count', param) log.debug("[getmultiotp] checkpolicypre returned %s" % max_count) if max_count <= 0: return sendError( response, "The policy forbids receiving OTP values for the token %s in this realm" % serial, 1) (res, pin, otpval, passw) = getOtp(serial, curTime=curTime) c.audit['success'] = True if int(res) < 0: ret['result'] = False if -1 == otpval: ret['description'] = "No Token with this serial number" if -2 == otpval: ret['description'] = "This Token does not support the getOtp function" if -3 == otpval: ret['description'] = "The user has more than one token" ret['serials'] = serials if -4 == otpval: ret['description'] = "No Token found for this user" if -5 == otpval: ret['description'] = "you need to provide a user or a serial" else: ret['result'] = True ret['otpval'] = otpval ret['pin'] = pin ret['pass'] = passw Session.commit() return sendResult(response, ret, 0) except PolicyException as pe: log.error("[getotp] gettoken/getotp policy failed: %r" % pe) log.error("[getotp] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[getotp] gettoken/getotp failed: %r" % e) log.error("[getotp] %s" % traceback.format_exc()) Session.rollback() return sendError(response, "gettoken/getotp failed: %s" % unicode(e), 0) finally: Session.close() log.debug('[getotp] done')
def checkstatus(self): """ method: ocra/checkstatus description: Methode zur assynchronen Ueberpruefungen eines Challenge Response Valiadation requests arguments: * transactionid: (required one of - string - (hex)) Dies ist eine Transaktions-ID, die bei der Challenge ausgegeben wurde. * serial: (required one of - string) die Serien Nummer des OCRA Token * user: (required one of - string) die Benutzer eines Tokens required is one of (user,serial,transactionid) returns: A JSON response:: { "version": "LinOTP 2.4", "jsonrpc": "2.0", "result": { "status": true, "value": [ { "serial": SERIENNUMMER1, "transactionid": TRANSACTIONID1, "received_tan": true, "valid_tan": true, "failcount": 0 }, { "serial": SERIENNUMMER1, "transactionid": TRANSACTIONID2, "received_tan": false, "valid_tan": false, "failcount": 0 }, { "serial": SERIENNUMMER2, "transactionid": TRANSACTIONID3, "received_tan": true, "valid_tan": false, "failcount": 2 }, ] }, "id": 0 } exception: """ res = {} description = 'ocra/checkstatus: check the token status - for assynchronous verification. Missing parameter: You need to provide one of the parameters "transactionid", "user" or "serial"' try: param = getLowerParams(request.params) log.debug("[checkstatus] check OCRA token status: %r" % param) checkPolicyPre('ocra', "status") transid = getParam(param, 'transactionid' , optional) user = getUserFromParam(param, optional) #user = getParam(param, 'user' ,optional) serial = getParam(param, 'serial' , optional) if transid is None and user.isEmpty() and serial is None: ## raise exception log.exception("[ocra/checkstatus] : missing transactionid, user or serial number for token") raise ParameterError("Usage: %s" % description, id=77) tokens = [] serials = set() status = [] if serial is not None: serials.add(serial) ## if we have a transaction, get serial from this challenge if transid is not None : ocraChallenge = None try: ocraChallenge = OcraTokenClass.getTransaction(transid) except: pass if ocraChallenge is not None: serials.add(ocraChallenge.tokenserial) ## if we have a serial number of token if len(serials) > 0: for serial in serials: tokens.extend(getTokens4UserOrSerial(serial=serial)) ## if we have a user if user.isEmpty() == False: try: tokens.extend(getTokens4UserOrSerial(user=user)) except: log.warning("no token or user %r found!" % user) for token in tokens: if token.getType() == 'ocra': challenges = [] if transid is None: serial = token.getSerial() challenges = OcraTokenClass.getTransactions4serial(serial) else: challenges.append(OcraTokenClass.getTransaction(transid)) for challenge in challenges: stat = token.getStatus(challenge.transid) if stat is not None and len(stat) > 0: status.append(stat) res['values'] = status c.audit['success'] = res Session.commit() return sendResult(response, res, 1) except PolicyException as pe: log.exception("[checkstatus] policy failed: %r" % pe) Session.rollback() return sendError(response, unicode(pe)) except Exception as exx: log.exception("[checkstatus] failed: %r" % exx) Session.rollback() return sendResult(response, unicode(exx), 0) finally: Session.close() log.debug('[ocra/checkstatus] done')
def import_users(self): """ import users from a csv file into an dedicated sql resolver """ try: params = self.request_params # -------------------------------------------------------------- -- # processing required arguments try: data_file = request.files["file"] resolver_name = params["resolver"] except KeyError as exx: log.error("Missing parameter: %r", exx) raise ParameterError("Missing parameter: %r" % exx) if resolver_name == current_app.config["ADMIN_RESOLVER_NAME"]: raise DeleteForbiddenError( f"default admin resolver {resolver_name} is not allowed " "to be overwritten!") groupid = resolver_name # process file upload data data = data_file # -- ----------------------------------------------------------- -- # In case of form post requests, it is a "instance" of FileStorage # i.e. the Filename is selected in the browser and the data is # transferred in an iframe. # see: http://jquery.malsup.com/form/#sample4 # -- ----------------------------------------------------------- -- if isinstance(data_file, FileStorage): data = data_file.read() data = data.decode() # -------------------------------------------------------------- -- # process the other arguments dryrun = boolean(params.get("dryrun", False)) passwords_in_plaintext = boolean( params.get("passwords_in_plaintext", False)) file_format = params.get("format", "csv") if file_format in ("password", "passwd"): column_mapping = { "userid": 2, "username": 0, "phone": 8, "mobile": 7, "email": 9, "surname": 5, "givenname": 4, "password": 1, } format_reader = PasswdFormatReader() elif file_format in ("csv"): skip_header = boolean(params.get("skip_header", False)) if skip_header: data = "\n".join(data.split("\n")[1:]) column_mapping = { "username": 0, "userid": 1, "surname": 2, "givenname": 3, "email": 4, "phone": 5, "mobile": 6, "password": 7, } delimiter = str(params.get("delimiter", ",")) quotechar = str(params.get("quotechar", '"')) format_reader = DefaultFormatReader() format_reader.delimiter = delimiter format_reader.quotechar = quotechar column_mapping = params.get("column_mapping", column_mapping) else: raise Exception("unspecified file foramt") # we have to convert the column_mapping back into an dict if isinstance(column_mapping, str): column_mapping = json.loads(column_mapping) # prevent overwrite of existing unmanaged resolver checkPolicyPre("system", "setResolver") resolvers = getResolverList() if resolver_name in resolvers: if not resolvers[resolver_name].get("readonly", False): raise Exception("Unmanged resolver with same name: %r" " already exists!" % resolver_name) # -------------------------------------------------------------- -- # feed the engine :) # use a LinOTP Database context for Sessions and Engine db_context = LinOTP_DatabaseContext(SqlSession=db.session, SqlEngine=db.engine) # define the import into an SQL database + resolver import_handler = SQLImportHandler( groupid=groupid, resolver_name=resolver_name, database_context=db_context, ) # create the UserImporter with the required mapping user_import = UserImport(import_handler) user_import.set_mapping(column_mapping) # and run the data processing result = user_import.import_csv_users( data, dryrun=dryrun, format_reader=format_reader, passwords_in_plaintext=passwords_in_plaintext, ) if dryrun: return sendResult(response, result) # -------------------------------------------------------------- -- # create / extend target realm for the resolver resolver_spec = import_handler.get_resolver_spec() db.session.commit() return sendResult(response, result) except PolicyException as pexx: log.error("Error during user import: %r", pexx) db.session.rollback() return sendError(response, "%r" % pexx, 1) except Exception as exx: log.error("Error during user import: %r", exx) db.session.rollback() return sendError(response, exx) finally: log.debug("done")
def tokenview_flexi(self): """ This function is used to fill the flexigrid. Unlike the complex /admin/show function, it only returns a simple array of the tokens. """ param = request.params try: # serial = getParam(param,"serial",optional) c.page = getParam(param, "page", optional) c.filter = getParam(param, "query", optional) c.qtype = getParam(param, "qtype", optional) c.sort = getParam(param, "sortname", optional) c.dir = getParam(param, "sortorder", optional) c.psize = getParam(param, "rp", optional) filter_all = None filter_realm = None user = User() if c.qtype == "loginname": if "@" in c.filter: (login, realm) = c.filter.split("@") user = User(login, realm) else: user = User(c.filter) elif c.qtype == "all": filter_all = c.filter elif c.qtype == "realm": filter_realm = c.filter # check admin authorization res = checkPolicyPre("admin", "show", param, user=user) filterRealm = res["realms"] # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. pol = getAdminPolicies("show") # If there are no admin policies, we are allowed to see all realms if not pol["active"]: filterRealm = ["*"] # check if we only want to see ONE realm or see all realms we are allowerd to see. if filter_realm: if filter_realm in filterRealm or "*" in filterRealm: filterRealm = [filter_realm] log.debug( "[tokenview_flexi] admin >%s< may display the following realms: %s" % (pol["admin"], pol["realms"]) ) log.debug("[tokenview_flexi] page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir)) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 log.debug( "[tokenview_flexi] calling TokenIterator for user=%s@%s, filter=%s, filterRealm=%s" % (user.login, user.realm, filter_all, filterRealm) ) c.tokenArray = TokenIterator( user, None, c.page, c.psize, filter_all, c.sort, c.dir, filterRealm=filterRealm ) c.resultset = c.tokenArray.getResultSetInfo() # If we have chosen a page to big! lines = [] for tok in c.tokenArray: lines.append( { "id": tok["LinOtp.TokenSerialnumber"], "cell": [ tok["LinOtp.TokenSerialnumber"], tok["LinOtp.Isactive"], tok["User.username"], tok["LinOtp.RealmNames"], tok["LinOtp.TokenType"], tok["LinOtp.FailCount"], tok["LinOtp.TokenDesc"], tok["LinOtp.MaxFail"], tok["LinOtp.OtpLen"], tok["LinOtp.CountWindow"], tok["LinOtp.SyncWindow"], tok["LinOtp.Userid"], tok["LinOtp.IdResolver"], ], } ) # We need to return 'page', 'total', 'rows' response.content_type = "application/json" res = {"page": int(c.page), "total": c.resultset["tokens"], "rows": lines} c.audit["success"] = True Session.commit() return json.dumps(res, indent=3) except PolicyException as pe: log.error("[tokenview_flexi] Error during checking policies: %r" % pe) log.error("[tokenview_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[tokenview_flexi] failed: %r" % e) log.error("[tokenview_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, e) finally: Session.close() log.debug("[tokenview_flexi] done")
def tokenview_flexi(self): ''' This function is used to fill the flexigrid. Unlike the complex /admin/show function, it only returns a simple array of the tokens. ''' param = request.params try: #serial = getParam(param,"serial",optional) c.page = getParam(param, "page", optional) c.filter = getParam(param, "query", optional) c.qtype = getParam(param, "qtype", optional) c.sort = getParam(param, "sortname", optional) c.dir = getParam(param, "sortorder", optional) c.psize = getParam(param, "rp", optional) filter_all = None filter_realm = None user = User() if c.qtype == "loginname": if "@" in c.filter: (login, realm) = c.filter.split("@") user = User(login, realm) else: user = User(c.filter) elif c.qtype == "all": filter_all = c.filter elif c.qtype == "realm": filter_realm = c.filter # check admin authorization res = checkPolicyPre('admin', 'show', param, user=user) filterRealm = res['realms'] # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. pol = getAdminPolicies("show") # If there are no admin policies, we are allowed to see all realms if not pol['active']: filterRealm = ["*"] # check if we only want to see ONE realm or see all realms we are allowerd to see. if filter_realm: if filter_realm in filterRealm or '*' in filterRealm: filterRealm = [filter_realm] log.debug( "[tokenview_flexi] admin >%s< may display the following realms: %s" % (pol['admin'], pol['realms'])) log.debug( "[tokenview_flexi] page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir)) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 log.debug( "[tokenview_flexi] calling TokenIterator for user=%s@%s, filter=%s, filterRealm=%s" % (user.login, user.realm, filter_all, filterRealm)) c.tokenArray = TokenIterator(user, None, c.page, c.psize, filter_all, c.sort, c.dir, filterRealm=filterRealm) c.resultset = c.tokenArray.getResultSetInfo() # If we have chosen a page to big! lines = [] for tok in c.tokenArray: # Arrange the table more helpfully. lines.append({ 'id': tok['LinOtp.TokenSerialnumber'], 'cell': [ tok['LinOtp.TokenSerialnumber'], tok['LinOtp.TokenType'], tok['LinOtp.TokenDesc'], tok['LinOtp.Isactive'], tok['User.username'], tok['LinOtp.Userid'], tok['LinOtp.FailCount'], tok['LinOtp.MaxFail'], tok['LinOtp.OtpLen'], tok['LinOtp.CountWindow'], tok['LinOtp.SyncWindow'], ] }) # We need to return 'page', 'total', 'rows' response.content_type = 'application/json' res = { "page": int(c.page), "total": c.resultset['tokens'], "rows": lines } c.audit['success'] = True Session.commit() return json.dumps(res, indent=3) except PolicyException as pe: log.error("[tokenview_flexi] Error during checking policies: %r" % pe) log.error("[tokenview_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[tokenview_flexi] failed: %r" % e) log.error("[tokenview_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, e) finally: Session.close() log.debug("[tokenview_flexi] done")
def getotp(self): ''' This function is used to retrieve the current otp value for a given user or a given serial If the user has more than one token, the list of the tokens is returend. method: gettoken/getotp arguments: user - username / loginname realm - additional realm to match the user to a useridresolver serial - the serial number of the token curTime - used ONLY for internal testing: datetime.datetime object returns: JSON response ''' getotp_active = config.get("linotpGetotp.active") if "True" != getotp_active: return sendError(response, "getotp is not activated.", 0) param = request.params ret = {} res = -1 otpval = "" passw = "" serials = [] try: serial = getParam(param, "serial", optional) user = getUserFromParam(param, optional) curTime = getParam(param, "curTime", optional) c.audit['user'] = user.login if "" != user.login: c.audit['realm'] = user.realm or getDefaultRealm() if serial: log.debug("[getotp] retrieving OTP value for token %s" % serial) elif user.login: log.debug("[getotp] retrieving OTP value for token for user %s@%s" % (user.login, user.realm)) toks = getTokens4UserOrSerial(user, serial) tokennum = len(toks) if tokennum > 1: log.debug("[getotp] The user has more than one token. Returning the list of serials") res = -3 for token in toks: serials.append(token.getSerial()) elif 1 == tokennum: serial = toks[0].getSerial() log.debug("[getotp] retrieving OTP for token %s for user %s@%s" % (serial, user.login, user.realm)) else: log.debug("[getotp] no token found for user %s@%s" % (user.login, user.realm)) res = -4 else: res = -5 # if a serial was given or a unique serial could be received from the given user. if serial: max_count = checkPolicyPre('gettoken', 'max_count', param) log.debug("[getmultiotp] checkpolicypre returned %s" % max_count) if max_count <= 0: return sendError(response, "The policy forbids receiving OTP values for the token %s in this realm" % serial , 1) (res, pin, otpval, passw) = getOtp(serial, curTime=curTime) c.audit['success'] = True if int(res) < 0: ret['result'] = False if -1 == otpval: ret['description'] = "No Token with this serial number" if -2 == otpval: ret['description'] = "This Token does not support the getOtp function" if -3 == otpval: ret['description'] = "The user has more than one token" ret['serials'] = serials if -4 == otpval: ret['description'] = "No Token found for this user" if -5 == otpval: ret['description'] = "you need to provide a user or a serial" else: ret['result'] = True ret['otpval'] = otpval ret['pin'] = pin ret['pass'] = passw Session.commit() return sendResult(response, ret , 0) except PolicyException as pe: log.exception("[getotp] gettoken/getotp policy failed: %r" % pe) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.exception("[getotp] gettoken/getotp failed: %r" % e) Session.rollback() return sendError(response, "gettoken/getotp failed: %s" % unicode(e), 0) finally: Session.close() log.debug('[getotp] done')
def tokeninfo(self): """ this returns the contents of /admin/show?serial=xyz in an html format """ param = self.request_params try: try: serial = param["serial"] except KeyError: raise ParameterError("Missing parameter: 'serial'") filterRealm = "" # check admin authorization res = checkPolicyPre("admin", "show", param) # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. filterRealm = ["*"] if res["active"] and res["realms"]: filterRealm = res["realms"] log.info( "[tokeninfo] admin >%s< may display the following realms:" " %s", res["admin"], filterRealm, ) log.info("[tokeninfo] displaying tokens: serial: %s", serial) toks = TokenIterator( User("", "", ""), serial, filterRealm=filterRealm ) # now row by row lines = [] for tok in toks: lines.append(tok) if len(lines) > 0: c.tokeninfo = lines[0] else: c.tokeninfo = {} for k in c.tokeninfo: if "LinOtp.TokenInfo" == k: try: # Try to convert string to Dictionary c.tokeninfo["LinOtp.TokenInfo"] = json.loads( c.tokeninfo["LinOtp.TokenInfo"] ) except BaseException: pass return render("/manage/tokeninfo.mako").decode("utf-8") except PolicyException as pe: log.error("[tokeninfo] Error during checking policies: %r", pe) db.session.rollback() return sendError(response, pe, 1) except Exception as exx: log.error("[tokeninfo] failed! %r", exx) db.session.rollback() return sendError(response, exx)
def getmultiotp(self): ''' This function is used to retrieve multiple otp values for a given user or a given serial If the user has more than one token, the list of the tokens is returend. method: gettoken/getmultiotp arguments: serial - the serial number of the token count - number of otp values to return curTime - used ONLY for internal testing: datetime.datetime object returns: JSON response ''' getotp_active = config.get("linotpGetotp.active") if "True" != getotp_active: return sendError(response, "getotp is not activated.", 0) param = request.params ret = {} try: serial = getParam(param, "serial", required) count = int(getParam(param, "count", required)) curTime = getParam(param, "curTime", optional) view = getParam(param, "view", optional) r1 = checkPolicyPre('admin', 'getotp', param) log.debug("[getmultiotp] admin-getotp returned %s" % r1) max_count = checkPolicyPre('gettoken', 'max_count', param) log.debug("[getmultiotp] checkpolicypre returned %s" % max_count) if count > max_count: count = max_count log.debug("[getmultiotp] retrieving OTP value for token %s" % serial) ret = get_multi_otp(serial, count=int(count), curTime=curTime) ret["serial"] = serial c.audit['success'] = True Session.commit() if view: c.ret = ret return render('/manage/multiotp_view.mako') else: return sendResult(response, ret , 0) except PolicyException as pe: log.exception("[getotp] gettoken/getotp policy failed: %r" % pe) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.exception("[getmultiotp] gettoken/getmultiotp failed: %r" % e) Session.rollback() return sendError(response, "gettoken/getmultiotp failed: %s" % unicode(e), 0) finally: Session.close() log.debug("[getmultiotp] done")
def userview_flexi(self): """ This function is used to fill the flexigrid. Unlike the complex /admin/userlist function, it only returns a simple array of the tokens. """ param = self.request_params try: c.page = param.get("page") c.filter = param.get("query") qtype = param.get("qtype") c.sort = param.get("sortname") c.dir = param.get("sortorder") c.psize = param.get("rp") c.realm = param.get("realm") user = getUserFromParam(param) # check admin authorization # check if we got a realm or resolver, that is ok! checkPolicyPre( "admin", "userlist", {"user": user.login, "realm": c.realm} ) if c.filter == "": c.filter = "*" log.debug( "[userview_flexi] page: %s, filter: %s, sort: %s, dir: %s", c.page, c.filter, c.sort, c.dir, ) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 c.userArray = getUserList( {qtype: c.filter, "realm": c.realm}, user ) c.userNum = len(c.userArray) lines = [] for u in c.userArray: # shorten the useridresolver, to get a better display value resolver_display = "" if "useridresolver" in u: if len(u["useridresolver"].split(".")) > 3: resolver_display = ( u["useridresolver"].split(".")[3] + " (" + u["useridresolver"].split(".")[1] + ")" ) else: resolver_display = u["useridresolver"] lines.append( { "id": u["username"], "cell": [ (u["username"]) if "username" in u else (""), (resolver_display), (u["surname"]) if "surname" in u else (""), (u["givenname"]) if "givenname" in u else (""), (u["email"]) if "email" in u else (""), (u["mobile"]) if "mobile" in u else (""), (u["phone"]) if "phone" in u else (""), (u["userid"]) if "userid" in u else (""), ], } ) # sorting reverse = False sortnames = { "username": 0, "useridresolver": 1, "surname": 2, "givenname": 3, "email": 4, "mobile": 5, "phone": 6, "userid": 7, } if c.dir == "desc": reverse = True lines = sorted( lines, key=lambda user: user["cell"][sortnames[c.sort]], reverse=reverse, ) # end: sorting # reducing the page if c.page and c.psize: page = int(c.page) psize = int(c.psize) start = psize * (page - 1) end = start + psize lines = lines[start:end] # We need to return 'page', 'total', 'rows' res = {"page": int(c.page), "total": c.userNum, "rows": lines} g.audit["success"] = True db.session.commit() return sendResult(response, res) except PolicyException as pe: log.error( "[userview_flexi] Error during checking policies: %r", pe ) db.session.rollback() return sendError(response, pe, 1) except Exception as exx: log.error("[userview_flexi] failed: %r", exx) db.session.rollback() return sendError(response, exx)
def setPin(self): """ method: api/helpdesk/setPin description: This function sets the PIN of the token arguments: * serial - required * pin - optional - uses random pin instead returns: an array with the list of affected serial numbers """ res = {} try: params = self.request_params serial = params.get("serial") if not serial: raise ParameterError("Missing parameter: 'serial'") tokens = getTokens4UserOrSerial(serial=serial) result = [] for token in tokens: owner = get_token_owner(token) current_serial = token.getSerial() pin = params.get( 'pin', createRandomPin(owner, min_pin_length=6)) # as the parameter pin in the params is evaluated by # the checkPolicyPre and checkPolicyPost we need to put the # parameter pin and current_serial into the params params['pin'] = pin params['serial'] = current_serial # set pin is done by the admin/set with the parameter pin checkPolicyPre( 'admin', method='set', param=params, user=owner) token.setPin(pin) # while in the pre checks for method='set' the post checks # for 'setPin' which is used to determin if a new pin has to # be generated res = checkPolicyPost( 'admin', 'setPin', param=params, user=owner) pin = res.get('new_pin', pin) info = { 'message': ('A new pin ${Pin} has been set for your ' 'token: ${serial}'), 'Subject': 'new pin set for token ${serial}', 'Pin': pin, 'serial': current_serial, } notify_user(owner, 'setPin', info, required=True) result.append(serial) c.audit['success'] = True c.audit['info'] = result Session.commit() return sendResult(response, result) except PolicyException as pex: log.exception('[setPin] policy failed %r') Session.rollback() return sendError(response, pex, 1) except Exception as exx: log.exception('[setPin] error while setting pin') Session.rollback() return sendError(response, exx, 0) finally: Session.close()
def enroll(self): """ method: api/helpdesk/enroll description: method to enroll a token as helpdesk arguments: * type: the token type, currently only 'email' * user: the new token owner * realm: (optional) the realm the user belongs to - used to identify the user returns: success as boolean """ ret = False response_detail = {} params = self.request_params try: if 'user' not in params: raise ParameterError('missing parameter: user!') if 'type' not in params: raise ParameterError('missing parameter: type!') # --------------------------------------------------------------- -- # determine token class token_cls_alias = params.get("type") lower_alias = token_cls_alias.lower() if lower_alias not in tokenclass_registry: raise TokenAdminError('admin/init failed: unknown token ' 'type %r' % token_cls_alias, id=1610) token_cls = tokenclass_registry.get(lower_alias) # --------------------------------------------------------------- -- # call the token class hook in order to enrich/overwrite the # parameters helper_params = token_cls.get_helper_params_pre(params) params.update(helper_params) # --------------------------------------------------------------- -- # fetch user from parameters. user = getUserFromParam(params) # --------------------------------------------------------------- -- # create a new pin according to the policies if 'pin' not in params: params['pin'] = createRandomPin(user, min_pin_length=6) # --------------------------------------------------------------- -- if 'otpkey' not in params: params['genkey'] = '1' # --------------------------------------------------------------- -- # check admin authorization res = checkPolicyPre('admin', 'init', params, user=user) # --------------------------------------------------------------- -- helper_params = token_cls.get_helper_params_post(params, user=user) params.update(helper_params) # --------------------------------------------------------------- -- # create new serial th = TokenHandler() serial = th.genSerial(token_cls_alias) params['serial'] = serial log.info("[init] initialize token. user: %s, serial: %s" % (user.login, serial)) # --------------------------------------------------------------- -- # scope_extension: we are in scope helpdesk # this is eg required to notify the emailtoken to use the # email from user if none is given as param params['::scope::'] = { 'helpdesk': True, 'user': user } (ret, token) = th.initToken(params, user) # --------------------------------------------------------------- -- # different token types return different information on # initialization (e.g. otpkey, pairing_url, etc) initDetail = token.getInitDetail(params, user) response_detail.update(initDetail) # --------------------------------------------------------------- -- # prepare data for audit if token is not None and ret is True: c.audit['serial'] = token.getSerial() c.audit['token_type'] = token.type c.audit['success'] = ret c.audit['user'] = user.login c.audit['realm'] = user.realm c.audit['action_detail'] += get_token_num_info() res = checkPolicyPost('admin', 'init', params, user=user) pin = res.get('new_pin', params['pin']) message = ("A new ${tokentype} token (${serial}) " "with pin '${Pin}' " "for ${givenname} ${surname} has been enrolled.") info = { 'message': message, 'Subject': 'New %s token enrolled' % token.type, 'Pin': pin, 'tokentype': token.type } info.update(response_detail) notify_user(user, 'enrollment', info, required=True) c.audit['action_detail'] += get_token_num_info() c.audit['success'] = ret return sendResult(response, ret) except PolicyException as pex: log.exception("Policy Exception while enrolling token") Session.rollback() return sendError(response, pex, 1) except Exception as exx: log.exception("Exception while enrolling token") Session.rollback() return sendError(response, exx, 1)
def getmultiotp(self): """ This function is used to retrieve multiple otp values for a given user or a given serial. If the user has more than one token, the list of the tokens is returend. method: gettoken/getmultiotp arguments: serial - the serial number of the token count - number of otp values to return curTime - used ONLY for internal testing: datetime.datetime object returns: JSON response """ getotp_active = boolean(getFromConfig("linotpGetotp.active", False)) if not getotp_active: return sendError(response, "getotp is not activated.", 0) param = self.request_params ret = {} try: serial = getParam(param, "serial", required) count = int(getParam(param, "count", required)) curTime = getParam(param, "curTime", optional) view = getParam(param, "view", optional) r1 = checkPolicyPre("admin", "getotp", param) log.debug("[getmultiotp] admin-getotp policy: %s", r1) max_count = checkPolicyPre("gettoken", "max_count", param) log.debug("[getmultiotp] maxcount policy: %s", max_count) if count > max_count: count = max_count log.debug("[getmultiotp] retrieving OTP value for token %s", serial) ret = get_multi_otp(serial, count=int(count), curTime=curTime) ret["serial"] = serial g.audit["success"] = True db.session.commit() if view: c.ret = ret return render("/selfservice/multiotp_view.mako").decode( "utf-8") else: return sendResult(response, ret, 0) except PolicyException as pe: log.error("[getotp] gettoken/getotp policy failed: %r", pe) db.session.rollback() return sendError(response, pe, 1) except Exception as exx: log.error("[getmultiotp] gettoken/getmultiotp failed: %r", exx) db.session.rollback() return sendError(response, "gettoken/getmultiotp failed: %r" % exx, 0)
def tokenview_flexi(self): ''' This function is used to fill the flexigrid. Unlike the complex /admin/show function, it only returns a simple array of the tokens. ''' param = self.request_params try: c.page = param.get("page") c.filter = param.get("query") c.qtype = param.get("qtype") c.sort = param.get("sortname") c.dir = param.get("sortorder") c.psize = param.get("rp") filter_all = None filter_realm = None user = User() if c.qtype == "loginname": # we take by default the given expression as a loginname, # especially if it contains a "*" wildcard. # it only might be more, a user and a realm, if there # is an '@' sign in the loginname and the part after the # last '@' sign is matching an existing realm user = User(login=c.filter) if "*" not in c.filter and "@" in c.filter: login, _ , realm = c.filter.rpartition("@") if realm.lower() in getRealms(): user = User(login, realm) if not user.exists(): user = User(login=c.filter) elif c.qtype == "all": filter_all = c.filter elif c.qtype == "realm": filter_realm = c.filter # check admin authorization res = checkPolicyPre('admin', 'show', param , user=user) filterRealm = res['realms'] # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. pol = getAdminPolicies("show") # If there are no admin policies, we are allowed to see all realms if not pol['active']: filterRealm = ["*"] # check if we only want to see ONE realm or see all realms we are allowerd to see. if filter_realm: if filter_realm in filterRealm or '*' in filterRealm: filterRealm = [filter_realm] log.debug("[tokenview_flexi] admin >%s< may display the following realms: %s" % (pol['admin'], pol['realms'])) log.debug("[tokenview_flexi] page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir)) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 log.debug("[tokenview_flexi] calling TokenIterator for user=%s@%s, filter=%s, filterRealm=%s" % (user.login, user.realm, filter_all, filterRealm)) c.tokenArray = TokenIterator(user, None, c.page , c.psize, filter_all, c.sort, c.dir, filterRealm=filterRealm) c.resultset = c.tokenArray.getResultSetInfo() # If we have chosen a page to big! lines = [] for tok in c.tokenArray: lines.append( {'id' : tok['LinOtp.TokenSerialnumber'], 'cell': [ tok['LinOtp.TokenSerialnumber'], tok['LinOtp.Isactive'], tok['User.username'], tok['LinOtp.RealmNames'], tok['LinOtp.TokenType'], tok['LinOtp.FailCount'], tok['LinOtp.TokenDesc'], tok['LinOtp.MaxFail'], tok['LinOtp.OtpLen'], tok['LinOtp.CountWindow'], tok['LinOtp.SyncWindow'], tok['LinOtp.Userid'], tok['LinOtp.IdResClass'].split('.')[-1], ] } ) # We need to return 'page', 'total', 'rows' res = { "page": int(c.page), "total": c.resultset['tokens'], "rows": lines } c.audit['success'] = True Session.commit() # The flexi handler should support std LinOTP output return sendResult(response, res) except PolicyException as pe: log.exception("[tokenview_flexi] Error during checking policies: %r" % pe) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.exception("[tokenview_flexi] failed: %r" % e) Session.rollback() return sendError(response, e) finally: Session.close()
def userview_flexi(self): ''' This function is used to fill the flexigrid. Unlike the complex /admin/userlist function, it only returns a simple array of the tokens. ''' param = request.params try: #serial = getParam(param,"serial",optional) c.page = getParam(param, "page", optional) c.filter = getParam(param, "query", optional) qtype = getParam(param, "qtype", optional) c.sort = getParam(param, "sortname", optional) c.dir = getParam(param, "sortorder", optional) c.psize = getParam(param, "rp", optional) c.realm = getParam(param, "realm", optional) user = getUserFromParam(param, optional) # check admin authorization # check if we got a realm or resolver, that is ok! checkPolicyPre('admin', 'userlist', { 'user': user.login, 'realm' : c.realm }, context=self.request_context) if c.filter == "": c.filter = "*" log.debug("[userview_flexi] page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir)) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 c.userArray = getUserList({ qtype:c.filter, 'realm':c.realm }, user) c.userNum = len(c.userArray) lines = [] for u in c.userArray: # shorten the useridresolver, to get a better display value resolver_display = "" if "useridresolver" in u: if len(u['useridresolver'].split(".")) > 3: resolver_display = u['useridresolver'].split(".")[3] + " (" + u['useridresolver'].split(".")[1] + ")" else: resolver_display = u['useridresolver'] lines.append( { 'id' : u['username'], 'cell': [ (u['username']) if u.has_key('username') else (""), (resolver_display), (u['surname']) if u.has_key('surname') else (""), (u['givenname']) if u.has_key('givenname') else (""), (u['email']) if u.has_key('email') else (""), (u['mobile']) if u.has_key('mobile') else (""), (u['phone']) if u.has_key('phone') else (""), (u['userid']) if u.has_key('userid') else (""), ] } ) # sorting reverse = False sortnames = { 'username' : 0, 'useridresolver' : 1, 'surname' : 2, 'givenname' : 3, 'email' : 4, 'mobile' :5, 'phone' : 6, 'userid' : 7 } if c.dir == "desc": reverse = True lines = sorted(lines, key=lambda user: user['cell'][sortnames[c.sort]], reverse=reverse, cmp=unicode_compare) # end: sorting # reducing the page if c.page and c.psize: page = int(c.page) psize = int(c.psize) start = psize * (page - 1) end = start + psize lines = lines[start:end] # We need to return 'page', 'total', 'rows' response.content_type = 'application/json' res = { "page": int(c.page), "total": c.userNum, "rows": lines } c.audit['success'] = True Session.commit() return sendResult(response, res) except PolicyException as pe: log.exception("[userview_flexi] Error during checking policies: %r" % pe) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.exception("[userview_flexi] failed: %r" % e) Session.rollback() return sendError(response, e) finally: Session.close() log.debug('[userview_flexi] done')
def search(self): ''' This functions searches within the audit trail It returns the audit information for the given search pattern method: audit/search arguments: key, value pairs as search patterns. * outform - optional: if set to "csv", than the token list will be given in CSV or: Usually the key=values will be locally AND concatenated. it a parameter or=true is passed, the filters will be OR concatenated. The Flexigrid provides us the following parameters: ('page', u'1'), ('rp', u'25'), ('sortname', u'number'), ('sortorder', u'asc'), ('query', u''), ('qtype', u'serial')] returns: JSON response or csv format ''' param = {} try: param.update(request.params) log.debug("[search] params: %s" % param) checkPolicyPre('audit', 'view', {}) log.debug("[search] params %r" % param) # remove the param outform (and other parameters that should not # be used for search! search_params = {} search_params.update(param) for key in ["outform", 'delimiter']: if key in search_params: del search_params[key] output_format = param.get("outform", 'json') or 'json' delimiter = param.get('delimiter', ',') or ',' audit_iterator = None log.debug("[search] search params %r" % search_params) audit_query = AuditQuery(search_params, audit) if output_format == "csv": filename = "linotp-audit.csv" response.content_type = "application/force-download" response.headers['Content-disposition'] = ( 'attachment; filename=%s' % filename) audit_iterator = CSVAuditIterator(audit_query, delimiter) else: response.content_type = 'application/json' audit_iterator = JSONAuditIterator(audit_query) c.audit['success'] = True Session.commit() return audit_iterator except PolicyException as pe: log.error("[getotp] gettoken/getotp policy failed: %r" % pe) log.error("[getotp] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[search] audit/search failed: %r" % e) log.error("[search] %s" % traceback.format_exc()) Session.rollback() return sendError(response, "audit/search failed: %s" % unicode(e), 0) finally: Session.close() log.debug('[search] done')
def userview_flexi(self): ''' This function is used to fill the flexigrid. Unlike the complex /admin/userlist function, it only returns a simple array of the tokens. ''' param = request.params try: #serial = getParam(param,"serial",optional) c.page = getParam(param, "page", optional) c.filter = getParam(param, "query", optional) qtype = getParam(param, "qtype", optional) c.sort = getParam(param, "sortname", optional) c.dir = getParam(param, "sortorder", optional) c.psize = getParam(param, "rp", optional) c.realm = getParam(param, "realm", optional) user = getUserFromParam(param, optional) # check admin authorization # check if we got a realm or resolver, that is ok! checkPolicyPre('admin', 'userlist', { 'user': user.login, 'realm': c.realm }) if c.filter == "": c.filter = "*" log.debug( "[userview_flexi] page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir)) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 c.userArray = getUserList({ qtype: c.filter, 'realm': c.realm }, user) c.userNum = len(c.userArray) lines = [] for u in c.userArray: # shorten the useridresolver, to get a better display value resolver_display = "" if "useridresolver" in u: if len(u['useridresolver'].split(".")) > 3: resolver_display = u['useridresolver'].split(".")[ 3] + " (" + u['useridresolver'].split(".")[1] + ")" else: resolver_display = u['useridresolver'] # Arrange the table more helpfully. lines.append({ 'id': u['username'], 'cell': [ (u['username']) if u.has_key('username') else (""), (u['givenname']) if u.has_key('givenname') else (""), (u['surname']) if u.has_key('surname') else (""), (u['email']) if u.has_key('email') else (""), (u['userid']) if u.has_key('userid') else (""), ] }) log.debug("[userview_flexi] Elements in c.userArray: %s" % len(c.userArray)) # sorting reverse = False sortnames = { 'username': 0, 'givenname': 1, 'surname': 2, 'email': 3, 'userid': 4 } if c.dir == "desc": reverse = True lines = sorted(lines, key=lambda user: user['cell'][sortnames[c.sort]], reverse=reverse, cmp=unicode_compare) # end: sorting # reducing the page if c.page and c.psize: page = int(c.page) psize = int(c.psize) start = psize * (page - 1) end = start + psize lines = lines[start:end] # We need to return 'page', 'total', 'rows' response.content_type = 'application/json' res = {"page": int(c.page), "total": c.userNum, "rows": lines} c.audit['success'] = True Session.commit() return json.dumps(res, indent=3) except PolicyException as pe: log.error("[userview_flexi] Error during checking policies: %r" % pe) log.error("[userview_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[userview_flexi] failed: %r" % e) log.error("[userview_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, e) finally: Session.close() log.debug('[userview_flexi] done')
def getotp(self): ''' This function is used to retrieve the current otp value for a given user or a given serial. If the user has more than one token, the list of the tokens is returend. method: gettoken/getotp arguments: user - username / loginname realm - additional realm to match the user to a useridresolver serial - the serial number of the token curTime - used ONLY for internal testing: datetime.datetime object returns: JSON response ''' getotp_active = config.get("GETOTP_ENABLED") if not getotp_active: return sendError(response, "getotp is not activated.", 0) param = self.request_params ret = {} res = -1 otpval = "" passw = "" serials = [] try: serial = getParam(param, "serial", optional) user = getUserFromParam(param) curTime = getParam(param, "curTime", optional) g.audit['user'] = user.login if "" != user.login: g.audit['realm'] = user.realm or getDefaultRealm() if serial: log.debug("[getotp] retrieving OTP value for token %s", serial) elif user.login: log.debug( "[getotp] retrieving OTP value for token for user " "%s@%s", user.login, user.realm) toks = getTokens4UserOrSerial(user, serial) tokennum = len(toks) if tokennum > 1: log.debug("[getotp] The user has more than one token." "Returning the list of serials") res = -3 for token in toks: serials.append(token.getSerial()) elif 1 == tokennum: serial = toks[0].getSerial() log.debug( "[getotp] retrieving OTP for token %s for user" " %s@%s", serial, user.login, user.realm) else: log.debug("[getotp] no token found for user %s@%s", user.login, user.realm) res = -4 else: res = -5 # if a serial was given or a unique serial could be # received from the given user. if serial: max_count = checkPolicyPre('gettoken', 'max_count', param) log.debug("[getmultiotp] max_count policy: %s", max_count) if max_count <= 0: return sendError( response, "The policy forbids receiving" " OTP values for the token %s in " "this realm" % serial, 1) (res, pin, otpval, passw) = getOtp(serial, curTime=curTime) g.audit['success'] = True if int(res) < 0: ret['result'] = False if -1 == otpval: ret['description'] = "No Token with this serial number" if -2 == otpval: ret['description'] = ("This Token does not support the" " getOtp function") if -3 == otpval: ret['description'] = "The user has more than one token" ret['serials'] = serials if -4 == otpval: ret['description'] = "No Token found for this user" if -5 == otpval: ret['description'] = ("you need to provide a user or " "a serial") else: ret['result'] = True ret['otpval'] = otpval ret['pin'] = pin ret['pass'] = passw db.session.commit() return sendResult(response, ret, 0) except PolicyException as pe: log.exception("[getotp] gettoken/getotp policy failed: %r", pe) db.session.rollback() return sendError(response, str(pe), 1) except Exception as exx: log.exception("[getotp] gettoken/getotp failed: %r", exx) db.session.rollback() return sendError(response, "gettoken/getotp failed: %s" % exx, 0)
def userview_flexi(self): """ This function is used to fill the flexigrid. Unlike the complex /admin/userlist function, it only returns a simple array of the tokens. """ param = request.params try: # serial = getParam(param,"serial",optional) c.page = getParam(param, "page", optional) c.filter = getParam(param, "query", optional) qtype = getParam(param, "qtype", optional) c.sort = getParam(param, "sortname", optional) c.dir = getParam(param, "sortorder", optional) c.psize = getParam(param, "rp", optional) c.realm = getParam(param, "realm", optional) user = getUserFromParam(param, optional) # check admin authorization # check if we got a realm or resolver, that is ok! checkPolicyPre("admin", "userlist", {"user": user.login, "realm": c.realm}) if c.filter == "": c.filter = "*" log.debug("[userview_flexi] page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir)) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 c.userArray = getUserList({qtype: c.filter, "realm": c.realm}, user) c.userNum = len(c.userArray) lines = [] for u in c.userArray: # shorten the useridresolver, to get a better display value resolver_display = "" if "useridresolver" in u: if len(u["useridresolver"].split(".")) > 3: resolver_display = ( u["useridresolver"].split(".")[3] + " (" + u["useridresolver"].split(".")[1] + ")" ) else: resolver_display = u["useridresolver"] lines.append( { "id": u["username"], "cell": [ (u["username"]) if u.has_key("username") else (""), (resolver_display), (u["surname"]) if u.has_key("surname") else (""), (u["givenname"]) if u.has_key("givenname") else (""), (u["email"]) if u.has_key("email") else (""), (u["mobile"]) if u.has_key("mobile") else (""), (u["phone"]) if u.has_key("phone") else (""), (u["userid"]) if u.has_key("userid") else (""), ], } ) # sorting reverse = False sortnames = { "username": 0, "useridresolver": 1, "surname": 2, "givenname": 3, "email": 4, "mobile": 5, "phone": 6, "userid": 7, } if c.dir == "desc": reverse = True lines = sorted( lines, key=lambda user: user["cell"][sortnames[c.sort]], reverse=reverse, cmp=unicode_compare ) # end: sorting # reducing the page if c.page and c.psize: page = int(c.page) psize = int(c.psize) start = psize * (page - 1) end = start + psize lines = lines[start:end] # We need to return 'page', 'total', 'rows' response.content_type = "application/json" res = {"page": int(c.page), "total": c.userNum, "rows": lines} c.audit["success"] = True Session.commit() return json.dumps(res, indent=3) except PolicyException as pe: log.error("[userview_flexi] Error during checking policies: %r" % pe) log.error("[userview_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[userview_flexi] failed: %r" % e) log.error("[userview_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, e) finally: Session.close() log.debug("[userview_flexi] done")
def userview_flexi(self): ''' This function is used to fill the flexigrid. Unlike the complex /admin/userlist function, it only returns a simple array of the tokens. ''' param = self.request_params try: c.page = param.get("page") c.filter = param.get("query") qtype = param.get("qtype") c.sort = param.get("sortname") c.dir = param.get("sortorder") c.psize = param.get("rp") c.realm = param.get("realm") user = getUserFromParam(param) # check admin authorization # check if we got a realm or resolver, that is ok! checkPolicyPre('admin', 'userlist', { 'user': user.login, 'realm': c.realm }) if c.filter == "": c.filter = "*" log.debug( "[userview_flexi] page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir)) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 c.userArray = getUserList({ qtype: c.filter, 'realm': c.realm }, user) c.userNum = len(c.userArray) lines = [] for u in c.userArray: # shorten the useridresolver, to get a better display value resolver_display = "" if "useridresolver" in u: if len(u['useridresolver'].split(".")) > 3: resolver_display = u['useridresolver'].split(".")[ 3] + " (" + u['useridresolver'].split(".")[1] + ")" else: resolver_display = u['useridresolver'] lines.append({ 'id': u['username'], 'cell': [ (u['username']) if 'username' in u else (""), (resolver_display), (u['surname']) if 'surname' in u else (""), (u['givenname']) if 'givenname' in u else (""), (u['email']) if 'email' in u else (""), (u['mobile']) if 'mobile' in u else (""), (u['phone']) if 'phone' in u else (""), (u['userid']) if 'userid' in u else (""), ] }) # sorting reverse = False sortnames = { 'username': 0, 'useridresolver': 1, 'surname': 2, 'givenname': 3, 'email': 4, 'mobile': 5, 'phone': 6, 'userid': 7 } if c.dir == "desc": reverse = True lines = sorted(lines, key=lambda user: user['cell'][sortnames[c.sort]], reverse=reverse) # end: sorting # reducing the page if c.page and c.psize: page = int(c.page) psize = int(c.psize) start = psize * (page - 1) end = start + psize lines = lines[start:end] # We need to return 'page', 'total', 'rows' res = {"page": int(c.page), "total": c.userNum, "rows": lines} c.audit['success'] = True Session.commit() return sendResult(response, res) except PolicyException as pe: log.exception( "[userview_flexi] Error during checking policies: %r" % pe) Session.rollback() return sendError(response, str(pe), 1) except Exception as e: log.exception("[userview_flexi] failed: %r" % e) Session.rollback() return sendError(response, e) finally: Session.close()
def request(self): """ method: ocra/request description: request a challenge for a user or for a serial number (token). arguments: * serial: (required - string) Serial number of the token, for which a challenge should be generated (either serial or user is required) * user: (required - string) The user for whose token a challenge should be generated If the user has more than one token, an error is returend. (either serial or user is required) * data: (required - String: URLendoced) These are the display data, that can be used to generate the challenge remark: the app will report a wrong qrcode, if the policy:: {'authentication' : qrtanurl=https://localhost } is not defined !! returns: A JSON respone:: { "version": "LinOTP 2.4", "jsonrpc": "2.0", "result": { "status": true, "value": false, }, "detail": { "transactionid" : TRANSAKTIONSID, "data" : DATAOBJECT, } } * transactionid: This is the transaction ID, that is used later for verifying the Return code /TAN. * data: This is an object (URL) which can be used to generate a QR-Code to be displayed to the QRTAN App """ res = {} description = 'ocra/request: request a challenge for a given user or token (serial). You must either provide a parameter "user" or a parameter "serial".' dataobj = "" try: param = getLowerParams(request.params) log.info("[request] saving default configuration: %r" % param) checkPolicyPre('ocra', "request") serial = getParam(param, 'serial', optional) user = getUserFromParam(param, optional) if user.isEmpty() and serial is None: ## raise exception log.exception("[request] user or serial is required") raise ParameterError("Usage: %s" % description, id=77) message = getParam(param, 'data' , optional) if message is None: message = '' ## ocra token tokens = getTokens4UserOrSerial(user, serial) if len(tokens) > 1 : error = ('More than one token found: unable to create challenge ' 'for (u:%r,s:%r)!' % (user, serial)) log.error(error) raise Exception(error) if len(tokens) == 0: error = ('No token found: unable to create challenge for' ' (u:%r,s:%r)!' % (user, serial)) log.error(error) raise Exception(error) ocra = tokens[0] (transId, challenge, res, url) = ocra.challenge(message) u = urlencode({'u':str(url.encode("utf-8"))}) uInfo = {'tr': transId, 'ch' : challenge, 'me': str(message.encode("utf-8")), 'u': u[2:]} detail = {"transactionid" : transId, 'challenge' : challenge, 'message' : str(message.encode("utf-8")), 'url' : str(url.encode("utf-8")), } ## create the app_url from the data''' dataobj = 'lseqr://req?%s' % (str(urlencode(uInfo))) ## append the signature to the url ''' signature = {'si' : ocra.signData(dataobj)} uInfo['si'] = signature dataobj = '%s&%s' % (dataobj, str(urlencode(signature))) detail["data"] = dataobj c.audit['success'] = res #c.audit['info'] += "%s=%s, " % (k, value) Session.commit() qr = getParam(param, 'qr', optional) if qr is not None: param['alt'] = detail return sendQRImageResult(response, dataobj, param) else: return sendResult(response, res, 1, opt=detail) except PolicyException as pe: log.exception("[request] policy failed: %r" % pe) Session.rollback() return sendError(response, unicode(pe)) except Exception as exx: log.exception("[request] failed: %r" % exx) Session.rollback() return sendError(response, unicode(exx)) finally: Session.close() log.debug("[request] done")
def search(self): ''' This functions searches within the audit trail It returns the audit information for the given search pattern method: audit/search arguments: key, value pairs as search patterns. * outform - optional: if set to "csv", than the token list will be given in CSV or: Usually the key=values will be locally AND concatenated. it a parameter or=true is passed, the filters will be OR concatenated. The Flexigrid provides us the following parameters: ('page', u'1'), ('rp', u'25'), ('sortname', u'number'), ('sortorder', u'asc'), ('query', u''), ('qtype', u'serial')] returns: JSON response or csv format ''' try: log.debug("[search] params: %s" % self.request_params) checkPolicyPre('audit', 'view', {}) # remove the param outform (and other parameters that should not # be used for search! search_params = self.request_params.copy() for key in ["outform", 'delimiter']: if key in search_params: del search_params[key] output_format = self.request_params.get("outform", 'json') or 'json' streamed_response = None audit_obj = current_app.audit_obj audit_query = AuditQuery(search_params, audit_obj) if output_format == "csv": delimiter = self.request_params.get('delimiter', ',') or ',' streamed_response = Response(stream_with_context( CSVAuditIterator(audit_query, delimiter)), mimetype='text/csv') streamed_response.headers.set('Content-disposition', 'attachment', filename='linotp-audit.csv') else: streamed_response = Response(stream_with_context( JSONAuditIterator(audit_query)), mimetype='application/json') g.audit['success'] = True db.session.commit() return streamed_response except PolicyException as pe: log.exception("[getotp] gettoken/getotp policy failed: %r" % pe) db.session.rollback() return sendError(response, str(pe), 1) except Exception as e: log.exception("[search] audit/search failed: %r" % e) db.session.rollback() return sendError(response, "audit/search failed", 0)
def calculateOtp(self): ''' ''' from linotp.lib.crypt import kdf2 from linotp.lib.ocra import OcraSuite from datetime import datetime from urlparse import urlparse from urlparse import parse_qs res = {} #description = 'ocra/calculateOtp: calculate the first otp from the given init2 response ' try: params = getLowerParams(request.params) log.debug("[calculateOtp]: %r" % params) checkPolicyPre('ocra', "calcOTP") sharedsecret = params.get('sharedsecret') activationcode = params.get('activationcode') nonce = params.get('nonce') ocrasuite = params.get('ocrasuite') challenge = params.get('challenge') counter = params.get('counter') ocrapin = params.get('ocrapin') nonce3 = params.get('no') ocrasuite3 = params.get('os') #serial3 = params.get('se') challenge = params.get('challenge') counter = params.get('counter') ocrapin = params.get('ocrapin') init1 = params.get('init1') init2 = params.get('init2') ## parse init1 ''' if init1 is not None: ## now parse the appurl for the ocrasuite ''' uri = urlparse(init1.replace('lseqr://', 'http://')) qs = uri.query qdict = parse_qs(qs) ocrasuite2 = qdict.get('os', None) if ocrasuite2 is not None and len(ocrasuite2) > 0: ocrasuite2 = ocrasuite2[0] if ocrasuite is None: ocrasuite = ocrasuite2 sharedsecret2 = qdict.get('sh', None) if sharedsecret2 is not None and len(sharedsecret2) > 0: sharedsecret2 = sharedsecret2[0] if sharedsecret is None: sharedsecret = sharedsecret2 ## parse init1 if init2 is not None: ## now parse the appurl for the ocrasuite uri = urlparse(init2.replace('lseqr://', 'http://')) qs = uri.query qdict = parse_qs(qs) challenge2 = qdict.get('ch', None) if challenge2 is not None and len(challenge2) > 0: challenge2 = challenge2[0] if challenge is None: challenge = challenge2 nonce2 = qdict.get('no', None) if nonce2 is not None and len(nonce2) > 0: nonce2 = nonce2[0] if nonce is None: nonce = nonce2 if ocrapin is None: ocrapin = '' if counter is None: counter = 0 if nonce3 is not None: nonce = unicode(nonce3) if ocrasuite3 is not None: ocrasuite = unicode(ocrasuite3) ## now we have all in place for the key derivation to create the new key ## sharedsecret, activationcode and nonce key_len = 20 if ocrasuite.find('-SHA256'): key_len = 32 elif ocrasuite.find('-SHA512'): key_len = 64 if sharedsecret is not None: sharedsecret = unicode(sharedsecret) if nonce is not None: nonce = unicode(nonce) if activationcode is not None: activationcode = unicode(activationcode) newkey = kdf2(sharedsecret, nonce, activationcode, len=key_len) ## hnewkey = binascii.hexlify(newkey) ocra = OcraSuite(ocrasuite) param = {} param['C'] = int(counter) param['Q'] = unicode(challenge) param['P'] = unicode(ocrapin) param['S'] = '' if ocra.T is not None: ## Default value for G is 1M, i.e., time-step size is one minute and the ## T represents the number of minutes since epoch time [UT]. now = datetime.now() stime = now.strftime("%s") itime = int(stime) param['T'] = itime data = ocra.combineData(**param) otp = ocra.compute(data, newkey) res = {'otp':otp} Session.commit() return sendResult(response, res, 1) except PolicyException as pe: log.exception("[ocra/calculateOtp] policy failed: %r" % pe) Session.rollback() return sendError(response, pe) except Exception as e: log.exception("[ocra/calculateOtp] failed: %r" % e) Session.rollback() return sendError(response, unicode(e), 0) finally: Session.close() log.debug('[ocra/calculateOtp] done')
def calculateOtp(self): ''' ''' from linotp.lib.crypto import kdf2 from linotp.tokens.ocra import OcraSuite from datetime import datetime from urlparse import urlparse from urlparse import parse_qs res = {} # description = 'ocra/calculateOtp: calculate the first # otp from the given init2 response ' try: params = getLowerParams(request.params) log.debug("[calculateOtp]: %r" % params) checkPolicyPre('ocra', "calcOTP") sharedsecret = params.get('sharedsecret') activationcode = params.get('activationcode') nonce = params.get('nonce') ocrasuite = params.get('ocrasuite') challenge = params.get('challenge') counter = params.get('counter') ocrapin = params.get('ocrapin') nonce3 = params.get('no') ocrasuite3 = params.get('os') challenge = params.get('challenge') counter = params.get('counter') ocrapin = params.get('ocrapin') init1 = params.get('init1') init2 = params.get('init2') if init1 is not None: # now parse the appurl for the ocrasuite uri = urlparse(init1.replace('lseqr://', 'http://')) qs = uri.query qdict = parse_qs(qs) ocrasuite2 = qdict.get('os', None) if ocrasuite2 is not None and len(ocrasuite2) > 0: ocrasuite2 = ocrasuite2[0] if ocrasuite is None: ocrasuite = ocrasuite2 sharedsecret2 = qdict.get('sh', None) if sharedsecret2 is not None and len(sharedsecret2) > 0: sharedsecret2 = sharedsecret2[0] if sharedsecret is None: sharedsecret = sharedsecret2 # parse init1 if init2 is not None: # now parse the appurl for the ocrasuite uri = urlparse(init2.replace('lseqr://', 'http://')) qs = uri.query qdict = parse_qs(qs) challenge2 = qdict.get('ch', None) if challenge2 is not None and len(challenge2) > 0: challenge2 = challenge2[0] if challenge is None: challenge = challenge2 nonce2 = qdict.get('no', None) if nonce2 is not None and len(nonce2) > 0: nonce2 = nonce2[0] if nonce is None: nonce = nonce2 if ocrapin is None: ocrapin = '' if counter is None: counter = 0 if nonce3 is not None: nonce = unicode(nonce3) if ocrasuite3 is not None: ocrasuite = unicode(ocrasuite3) # now we have all in place for the key derivation to create # the new key sharedsecret, activationcode and nonce key_len = 20 if ocrasuite.find('-SHA256'): key_len = 32 elif ocrasuite.find('-SHA512'): key_len = 64 if sharedsecret is not None: sharedsecret = unicode(sharedsecret) if nonce is not None: nonce = unicode(nonce) if activationcode is not None: activationcode = unicode(activationcode) newkey = kdf2(sharedsecret, nonce, activationcode, len=key_len) ocra = OcraSuite(ocrasuite) param = {} param['C'] = int(counter) param['Q'] = unicode(challenge) param['P'] = unicode(ocrapin) param['S'] = '' if ocra.T is not None: # Default value for G is 1M, i.e., time-step size is # one minute and the T represents the number of minutes # since epoch time [UT]. now = datetime.now() stime = now.strftime("%s") itime = int(stime) param['T'] = itime data = ocra.combineData(**param) otp = ocra.compute(data, newkey) res = {'otp': otp} Session.commit() return sendResult(response, res, 1) except PolicyException as pe: log.exception("[ocra/calculateOtp] policy failed: %r" % pe) Session.rollback() return sendError(response, pe) except Exception as e: log.exception("[ocra/calculateOtp] failed: %r" % e) Session.rollback() return sendError(response, unicode(e), 0) finally: Session.close()
def getmultiotp(self): ''' This function is used to retrieve multiple otp values for a given user or a given serial If the user has more than one token, the list of the tokens is returend. method: gettoken/getmultiotp arguments: serial - the serial number of the token count - number of otp values to return curTime - used ONLY for internal testing: datetime.datetime object returns: JSON response ''' getotp_active = config.get("linotpGetotp.active") if "True" != getotp_active: return sendError(response, "getotp is not activated.", 0) param = request.params ret = {} try: serial = getParam(param, "serial", required) count = int(getParam(param, "count", required)) curTime = getParam(param, "curTime", optional) view = getParam(param, "view", optional) r1 = checkPolicyPre('admin', 'getotp', param) log.debug("[getmultiotp] admin-getotp returned %s" % r1) max_count = checkPolicyPre('gettoken', 'max_count', param) log.debug("[getmultiotp] checkpolicypre returned %s" % max_count) if count > max_count: count = max_count log.debug("[getmultiotp] retrieving OTP value for token %s" % serial) ret = get_multi_otp(serial, count=int(count), curTime=curTime) ret["serial"] = serial c.audit['success'] = True Session.commit() if view: c.ret = ret return render('/manage/multiotp_view.mako') else: return sendResult(response, ret, 0) except PolicyException as pe: log.error("[getotp] gettoken/getotp policy failed: %r" % pe) log.error("[getotp] %s" % traceback.format_exc()) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.error("[getmultiotp] gettoken/getmultiotp failed: %r" % e) log.error("[getmultiotp] %s" % traceback.format_exc()) Session.rollback() return sendError(response, "gettoken/getmultiotp failed: %s" % unicode(e), 0) finally: Session.close() log.debug("[getmultiotp] done")
def tokens(self): ''' This function is used to fill the flexigrid. Unlike the complex /admin/show function, it only returns a simple array of the tokens. ''' param = self.request_params try: page = param.get("page", 1) qfilter = param.get("query") qtype = param.get("qtype", 'all') sort = param.get("sortname", ) direction = param.get("sortorder", "desc") psize = param.get("rp", 20) filter_all = None filter_realm = None user = User() if qtype == "loginname": # we take by default the given expression as a loginname, # especially if it contains a "*" wildcard. # it only might be more, a user and a realm, if there # is an '@' sign in the loginname and the part after the # last '@' sign is matching an existing realm user = User(login=qfilter) if "*" not in qfilter and "@" in qfilter: login, _, realm = qfilter.rpartition("@") if realm.lower() in getRealms(): user = User(login, realm) if not user.exists(): user = User(login=qfilter) elif qtype == "all": filter_all = qfilter elif qtype == "realm": filter_realm = qfilter # check admin authorization res = checkPolicyPre('admin', 'show', param, user=user) filterRealm = res['realms'] # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. pol = getAdminPolicies("show") # If there are no admin policies, we are allowed to see all realms if not pol['active']: filterRealm = ["*"] # check if we only want to see ONE realm or see all realms # we are allowerd to see. if filter_realm: if filter_realm in filterRealm or '*' in filterRealm: filterRealm = [filter_realm] tokenArray = TokenIterator( user, None, page, psize, filter_all, sort, direction, filterRealm=filterRealm) resultset = tokenArray.getResultSetInfo() # If we have chosen a page to big! lines = [] for tok in tokenArray: lines.append({ 'id': tok['LinOtp.TokenSerialnumber'], 'cell': [ tok['LinOtp.TokenSerialnumber'], tok['LinOtp.Isactive'], tok['User.username'], tok['LinOtp.RealmNames'], tok['LinOtp.TokenType'], tok['LinOtp.FailCount'], tok['LinOtp.TokenDesc'], tok['LinOtp.MaxFail'], tok['LinOtp.OtpLen'], tok['LinOtp.CountWindow'], tok['LinOtp.SyncWindow'], tok['LinOtp.Userid'], tok['LinOtp.IdResClass'].split('.')[-1], ] }) # We need to return 'page', 'total', 'rows' res = { "page": int(page), "total": resultset['tokens'], "rows": lines } c.audit['success'] = True Session.commit() return sendResult(response, res) except PolicyException as pex: log.exception("Error during checking policies") Session.rollback() return sendError(response, pex, 1) except Exception as exx: log.exception("tokens lookup failed!") Session.rollback() return sendError(response, exx) finally: Session.close()
def getmultiotp(self): ''' This function is used to retrieve multiple otp values for a given user or a given serial. If the user has more than one token, the list of the tokens is returend. method: gettoken/getmultiotp arguments: serial - the serial number of the token count - number of otp values to return curTime - used ONLY for internal testing: datetime.datetime object returns: JSON response ''' getotp_active = config.get("GETOTP_ENABLED") if not getotp_active: return sendError(response, "getotp is not activated.", 0) param = self.request_params ret = {} try: serial = getParam(param, "serial", required) count = int(getParam(param, "count", required)) curTime = getParam(param, "curTime", optional) view = getParam(param, "view", optional) r1 = checkPolicyPre('admin', 'getotp', param) log.debug("[getmultiotp] admin-getotp policy: %s", r1) max_count = checkPolicyPre('gettoken', 'max_count', param) log.debug("[getmultiotp] maxcount policy: %s", max_count) if count > max_count: count = max_count log.debug("[getmultiotp] retrieving OTP value for token %s", serial) ret = get_multi_otp(serial, count=int(count), curTime=curTime) ret["serial"] = serial g.audit['success'] = True db.session.commit() if view: c.ret = ret return render('/manage/multiotp_view.mako').decode('utf-8') else: return sendResult(response, ret, 0) except PolicyException as pe: log.exception("[getotp] gettoken/getotp policy failed: %r", pe) db.session.rollback() return sendError(response, str(pe), 1) except Exception as exx: log.exception("[getmultiotp] gettoken/getmultiotp failed: %r", exx) db.session.rollback() return sendError(response, "gettoken/getmultiotp failed: %r" % exx, 0)
def search(self): """ This functions searches within the audit trail It returns the audit information for the given search pattern method: audit/search arguments: key, value pairs as search patterns. * outform - optional: if set to "csv", than the token list will be given in CSV or: Usually the key=values will be locally AND concatenated. it a parameter or=true is passed, the filters will be OR concatenated. The Flexigrid provides us the following parameters: ('page', u'1'), ('rp', u'25'), ('sortname', u'number'), ('sortorder', u'asc'), ('query', u''), ('qtype', u'serial')] returns: JSON response or csv format """ try: log.debug("[search] params: %r", self.request_params) checkPolicyPre("audit", "view", {}) # remove the param outform (and other parameters that should not # be used for search! search_params = self.request_params.copy() for key in ["outform", "delimiter"]: if key in search_params: del search_params[key] output_format = ( self.request_params.get("outform", "json") or "json" ) delimiter = self.request_params.get("delimiter", ",") or "," audit_obj = current_app.audit_obj audit_query = AuditQuery(search_params, audit_obj) # ------------------------------------------------------------- -- # check if we are running with sqlite which does not support # streaming responses stream_output = True db_uri = current_app.config["SQLALCHEMY_BINDS"]["auditdb"] if db_uri.startswith("sqlite"): stream_output = False if output_format == "csv": audit_iterator = CSVAuditIterator(audit_query, delimiter) mimetype = "text/csv" reponse_headers_args = { "_key": "Content-disposition", "_value": "attachment", "filename": "linotp-audit.csv", } else: audit_iterator = JSONAuditIterator(audit_query) mimetype = "application/json" reponse_headers_args = {} if stream_output: audit_output = stream_with_context(audit_iterator) else: audit_output = "" try: while True: audit_output = audit_output + next(audit_iterator) except StopIteration: # continue if all data is joined pass streamed_response = Response(audit_output, mimetype=mimetype) if reponse_headers_args: streamed_response.headers.set(**reponse_headers_args) g.audit["success"] = True db.session.commit() return streamed_response except PolicyException as pe: log.error("[getotp] gettoken/getotp policy failedi: %r", pe) db.session.rollback() return sendError(response, pe, 1) except Exception as exx: log.error("[search] audit/search failed: %r", exx) db.session.rollback() return sendError(response, "audit/search failed", 0)
def tokenview_flexi(self): ''' This function is used to fill the flexigrid. Unlike the complex /admin/show function, it only returns a simple array of the tokens. ''' param = self.request_params try: c.page = param.get("page") c.filter = param.get("query") c.qtype = param.get("qtype") c.sort = param.get("sortname") c.dir = param.get("sortorder") c.psize = param.get("rp") filter_all = None filter_realm = None user = User() if c.qtype == "loginname": # we take by default the given expression as a loginname, # especially if it contains a "*" wildcard. # it only might be more, a user and a realm, if there # is an '@' sign in the loginname and the part after the # last '@' sign is matching an existing realm user = User(login=c.filter) if "*" not in c.filter and "@" in c.filter: login, _, realm = c.filter.rpartition("@") if realm.lower() in getRealms(): user = User(login, realm) if not user.exists(): user = User(login=c.filter) elif c.qtype == "all": filter_all = c.filter elif c.qtype == "realm": filter_realm = c.filter # check admin authorization res = checkPolicyPre('admin', 'show', param, user=user) filterRealm = res['realms'] # check if policies are active at all # If they are not active, we are allowed to SHOW any tokens. pol = getAdminPolicies("show") # If there are no admin policies, we are allowed to see all realms if not pol['active']: filterRealm = ["*"] # check if we only want to see ONE realm or see all realms we are allowerd to see. if filter_realm: if filter_realm in filterRealm or '*' in filterRealm: filterRealm = [filter_realm] log.debug( "[tokenview_flexi] admin >%s< may display the following realms: %s" % (pol['admin'], pol['realms'])) log.debug( "[tokenview_flexi] page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir)) if c.page is None: c.page = 1 if c.psize is None: c.psize = 20 log.debug( "[tokenview_flexi] calling TokenIterator for user=%s@%s, filter=%s, filterRealm=%s" % (user.login, user.realm, filter_all, filterRealm)) c.tokenArray = TokenIterator(user, None, c.page, c.psize, filter_all, c.sort, c.dir, filterRealm=filterRealm) c.resultset = c.tokenArray.getResultSetInfo() # If we have chosen a page to big! lines = [] for tok in c.tokenArray: uid = tok['LinOtp.Userid'] uid = uid.decode('utf-8') if isinstance(uid, bytes) else uid lines.append({ 'id': tok['LinOtp.TokenSerialnumber'], 'cell': [ tok['LinOtp.TokenSerialnumber'], tok['LinOtp.Isactive'], tok['User.username'], tok['LinOtp.RealmNames'], tok['LinOtp.TokenType'], tok['LinOtp.FailCount'], tok['LinOtp.TokenDesc'], tok['LinOtp.MaxFail'], tok['LinOtp.OtpLen'], tok['LinOtp.CountWindow'], tok['LinOtp.SyncWindow'], uid, tok['LinOtp.IdResClass'].split('.')[-1], ] }) # We need to return 'page', 'total', 'rows' res = { "page": int(c.page), "total": c.resultset['tokens'], "rows": lines } c.audit['success'] = True Session.commit() # The flexi handler should support std LinOTP output return sendResult(response, res) except PolicyException as pe: log.exception( "[tokenview_flexi] Error during checking policies: %r" % pe) Session.rollback() return sendError(response, str(pe), 1) except Exception as e: log.exception("[tokenview_flexi] failed: %r" % e) Session.rollback() return sendError(response, e) finally: Session.close()
def request(self): """ method: ocra/request description: request a challenge for a user or for a serial number (token). arguments: * serial: (required - string) Serial number of the token, for which a challenge should be generated (either serial or user is required) * user: (required - string) The user for whose token a challenge should be generated If the user has more than one token, an error is returend. (either serial or user is required) * data: (required - String: URLendoced) These are the display data, that can be used to generate the challenge remark: the app will report a wrong qrcode, if the policy:: {'authentication' : qrtanurl=https://localhost } is not defined !! returns: A JSON respone:: { "version": "LinOTP 2.4", "jsonrpc": "2.0", "result": { "status": true, "value": false, }, "detail": { "transactionid" : TRANSAKTIONSID, "data" : DATAOBJECT, } } * transactionid: This is the transaction ID, that is used later for verifying the Return code /TAN. * data: This is an object (URL) which can be used to generate a QR-Code to be displayed to the QRTAN App """ res = {} description = ('ocra/request: request a challenge for a given user or' ' token (serial). You must either provide a parameter ' '"user" or a parameter "serial".') dataobj = "" try: param = getLowerParams(request.params) log.info("[request] saving default configuration: %r" % param) checkPolicyPre('ocra', "request") serial = param.get('serial') user = getUserFromParam(param) if user.is_empty and serial is None: log.exception("[request] user or serial is required") raise ParameterError("Usage: %s" % description, id=77) if not serial: if not user.exists(): raise UserError("getUserId failed: no user >%s< found!" % user.login, id=1205) message = param.get('data') if message is None: message = '' # ocra token tokens = getTokens4UserOrSerial(user, serial) if len(tokens) > 1: error = ('More than one token found: unable to create ' 'challenge for (u:%r,s:%r)!' % (user, serial)) raise Exception(error) if len(tokens) == 0: error = ('No token found: unable to create challenge for' ' (u:%r,s:%r)!' % (user, serial)) raise Exception(error) ocra = tokens[0] (transId, challenge, res, url) = ocra.challenge(message) u = urlencode({'u': str(url.encode("utf-8"))}) uInfo = {'tr': transId, 'ch': challenge, 'me': str(message.encode("utf-8")), 'u': u[2:]} detail = {"transactionid": transId, 'challenge': challenge, 'message': str(message.encode("utf-8")), 'url': str(url.encode("utf-8")), } # create the app_url from the data dataobj = 'lseqr://req?%s' % (str(urlencode(uInfo))) # append the signature to the url signature = {'si': ocra.signData(dataobj)} uInfo['si'] = signature dataobj = '%s&%s' % (dataobj, str(urlencode(signature))) detail["data"] = dataobj c.audit['success'] = res Session.commit() qr = param.get('qr') if qr is not None: param['alt'] = detail return sendQRImageResult(response, dataobj, param) else: return sendResult(response, res, 1, opt=detail) except PolicyException as pe: log.exception("[request] policy failed: %r" % pe) Session.rollback() return sendError(response, unicode(pe)) except Exception as exx: log.exception("[request] failed: %r" % exx) Session.rollback() return sendError(response, unicode(exx)) finally: Session.close()
def search(self): ''' This functions searches within the audit trail It returns the audit information for the given search pattern method: audit/search arguments: key, value pairs as search patterns. * outform - optional: if set to "csv", than the token list will be given in CSV or: Usually the key=values will be locally AND concatenated. it a parameter or=true is passed, the filters will be OR concatenated. The Flexigrid provides us the following parameters: ('page', u'1'), ('rp', u'25'), ('sortname', u'number'), ('sortorder', u'asc'), ('query', u''), ('qtype', u'serial')] returns: JSON response or csv format ''' param = {} try: param.update(request.params) log.debug("[search] params: %s" % param) checkPolicyPre('audit', 'view', {}) # remove the param outform (and other parameters that should not # be used for search! search_params = {} search_params.update(param) for key in ["outform", 'delimiter']: if key in search_params: del search_params[key] output_format = param.get("outform", 'json') or 'json' delimiter = param.get('delimiter', ',') or ',' audit_iterator = None audit_query = AuditQuery(search_params, audit) if output_format == "csv": filename = "linotp-audit.csv" response.content_type = "application/force-download" response.headers['Content-disposition'] = ( 'attachment; filename=%s' % filename) audit_iterator = CSVAuditIterator(audit_query, delimiter) else: response.content_type = 'application/json' audit_iterator = JSONAuditIterator(audit_query) c.audit['success'] = True Session.commit() return audit_iterator except PolicyException as pe: log.exception("[getotp] gettoken/getotp policy failed: %r" % pe) Session.rollback() return sendError(response, unicode(pe), 1) except Exception as e: log.exception("[search] audit/search failed: %r" % e) Session.rollback() return sendError(response, "audit/search failed", 0) finally: Session.close()
def checkstatus(self): """ method: ocra/checkstatus description: Methode zur assynchronen Ueberpruefungen eines Challenge Response Valiadation requests arguments: * transactionid: (required one of - string - (hex)) Dies ist eine Transaktions-ID, die bei der Challenge ausgegeben wurde. * serial: (required one of - string) die Serien Nummer des OCRA Token * user: (required one of - string) die Benutzer eines Tokens required is one of (user,serial,transactionid) returns: A JSON response:: { "version": "LinOTP 2.4", "jsonrpc": "2.0", "result": { "status": true, "value": [ { "serial": SERIENNUMMER1, "transactionid": TRANSACTIONID1, "received_tan": true, "valid_tan": true, "failcount": 0 }, { "serial": SERIENNUMMER1, "transactionid": TRANSACTIONID2, "received_tan": false, "valid_tan": false, "failcount": 0 }, { "serial": SERIENNUMMER2, "transactionid": TRANSACTIONID3, "received_tan": true, "valid_tan": false, "failcount": 2 }, ] }, "id": 0 } exception: """ res = {} description = ('ocra/checkstatus: check the token status - ' 'for assynchronous verification. Missing parameter: ' 'You need to provide one of the parameters ' '"transactionid", "user" or "serial"') try: param = getLowerParams(request.params) log.debug("[checkstatus] check OCRA token status: %r" % param) checkPolicyPre('ocra', "status") transid = param.get('transactionid') user = getUserFromParam(param) serial = param.get('serial') if transid is None and user.is_empty and serial is None: # raise exception log.exception("[ocra/checkstatus] : missing transactionid, user or serial number for token") raise ParameterError("Usage: %s" % description, id=77) tokens = [] serials = set() status = [] if serial is not None: serials.add(serial) # if we have a transaction, get serial from this challenge if transid is not None: ocraChallenge = None try: ocraChallenge = OcraTokenClass.getTransaction(transid) except: pass if ocraChallenge is not None: serials.add(ocraChallenge.tokenserial) # if we have a serial number of token if len(serials) > 0: for serial in serials: tokens.extend(getTokens4UserOrSerial(serial=serial)) # if we have a user if not user.is_empty: try: tokens.extend(getTokens4UserOrSerial(user=user)) except: log.warning("no token or user %r found!" % user) for token in tokens: if token.getType() == 'ocra': challenges = [] if transid is None: serial = token.getSerial() challenges = OcraTokenClass.getTransactions4serial( serial) else: challenges.append(OcraTokenClass.getTransaction( transid)) for challenge in challenges: stat = token.getStatus(challenge.transid) if stat is not None and len(stat) > 0: status.append(stat) res['values'] = status c.audit['success'] = res Session.commit() return sendResult(response, res, 1) except PolicyException as pe: log.exception("[checkstatus] policy failed: %r" % pe) Session.rollback() return sendError(response, unicode(pe)) except Exception as exx: log.exception("[checkstatus] failed: %r" % exx) Session.rollback() return sendResult(response, unicode(exx), 0) finally: Session.close()