def check_yubikey(self): ''' This function is used to validate the output of a yubikey method: validate/check_yubikey :param pass: The password that consist of the static yubikey prefix and the otp :type pass: string :return: JSON Object returns: JSON response:: { "version": "LinOTP 2.4", "jsonrpc": "2.0", "result": { "status": true, "value": false }, "detail" : { "username": username, "realm": realm }, "id": 0 } ''' param = request.params passw = getParam(param, "pass", required) try: ok = False try: vh = ValidationHandler() ok, opt = vh.checkYubikeyPass(passw) c.audit['success'] = ok except AuthorizeException as exx: log.warning( "[check_yubikey] authorization failed for validate/check_yubikey: %r" % exx) c.audit['success'] = False c.audit['info'] = unicode(exx) ok = False Session.commit() return sendResult(response, ok, 0, opt=opt) except Exception as exx: log.exception("[check_yubikey] validate/check_yubikey failed: %r" % exx) c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, 0) finally: Session.close()
def pair(self): try: # ------------------------------------------------------------------ params = dict(**request.params) enc_response = params.get('pairing_response') if enc_response is None: raise Exception('Parameter missing') # ------------------------------------------------------------------ dec_response = decrypt_pairing_response(enc_response) token_type = dec_response.token_type pairing_data = dec_response.pairing_data if not hasattr(pairing_data, 'serial') or \ pairing_data.serial is None: raise ValidateError( 'Pairing responses with no serial attached ' 'are currently not implemented.') # ------------------------------------------------------------------ # TODO: pairing policy tokens = getTokens4UserOrSerial(None, pairing_data.serial) if not tokens: raise Exception('Invalid serial in pairing response') if len(tokens) > 1: raise Exception('Multiple tokens found. Pairing not possible') token = tokens[0] # ------------------------------------------------------------------ if token.type != token_type: raise Exception('Serial in pairing response doesn\'t match ' 'supplied token_type') # ------------------------------------------------------------------ token.pair(pairing_data) Session.commit() return sendResult(response, False) # ---------------------------------------------------------------------- except Exception: Session.rollback() return sendResult(response, False, 0, status=False) finally: Session.close()
def storeToken(self): log.debug('storeToken()') Session.add(self) Session.flush() Session.commit() log.debug('store token success') return True
def webkdc_userinfo(self): # Called by WebAuth via the Elm remctld scripts. # Returns information about whether the user owns any tokens. # TODO: Require some sort of session token. param = {} try: param.update(request.params) user = getUserFromParam(param, optionalOrRequired = True) if (user is not None and user.isEmpty() == False): (userid, idResolver, idResolverClass) = getUserId(user) sqlQuery = Session.query(model.Token).with_lockmode("update").filter( model.Token.LinOtpUserid == userid).filter( model.Token.LinOtpIdResClass == idResolverClass).filter( model.Token.LinOtpIsactive == 1) tokenList = [] for token in sqlQuery: tokenList.append(token.LinOtpTokenSerialnumber) Session.commit() return sendResult(response, tokenList, 0) except Exception as exx: log.error("[webkdc_userinfo] validate/webkdc_userinfo failed: %r" % exx) log.error("[webkdc_userinfo] %s" % traceback.format_exc()) Session.rollback() return sendError(response, u"validate/webkdc_userinfo failed: %s" % unicode(exx), 0) finally: Session.close()
def check_yubikey(self): ''' This function is used to validate the output of a yubikey method: validate/check_yubikey :param pass: The password that consist of the static yubikey prefix and the otp :type pass: string :return: JSON Object returns: JSON response:: { "version": "LinOTP 2.4", "jsonrpc": "2.0", "result": { "status": true, "value": false }, "detail" : { "username": username, "realm": realm }, "id": 0 } ''' param = request.params passw = getParam(param, "pass", required) try: ok = False try: ok, opt = checkYubikeyPass(passw) c.audit['success'] = ok except AuthorizeException as exx: log.warning("[check_yubikey] authorization failed for validate/check_yubikey: %r" % exx) c.audit['success'] = False c.audit['info'] = unicode(exx) ok = False Session.commit() return sendResult(response, ok, 0, opt=opt) except Exception as exx: log.error("[check_yubikey] validate/check_yubikey failed: %r" % exx) log.error("[check_yubikey] %s" % traceback.format_exc()) c.audit['info'] = unicode(exx) Session.rollback() return sendError(response, u"validate/check_yubikey failed: %s" % unicode(exx), 0) finally: Session.close() log.debug('[check_yubikey] done')
def login(self): log.debug("[login] selfservice login screen") identity = request.environ.get('repoze.who.identity') if identity is not None: # After login We always redirect to the start page redirect("/") res = {} try: c.defaultRealm = getDefaultRealm() res = getRealms() c.realmArray = [] #log.debug("[login] %s" % str(res) ) for (k, v) in res.items(): c.realmArray.append(k) c.realmbox = getRealmBox() log.debug("[login] displaying realmbox: %i" % int(c.realmbox)) Session.commit() response.status = '%i Logout from LinOTP selfservice' % LOGIN_CODE return render('/selfservice/login.mako') except Exception as e: log.exception('[login] failed %r' % e) Session.rollback() return sendError(response, e) finally: Session.close()
def delete_all(self): """ method: reporting/delete_all description: delete the reporting database table returns: dict in which value is the number of deleted rows exception: if an error occurs an exception is serialized and returned """ try: result = delete_reporting() Session.commit() return sendResult(response, result) except PolicyException as policy_exception: log.exception(policy_exception) Session.rollback() return sendError(response, unicode(policy_exception), 1) except Exception as exc: log.exception(exc) Session.rollback() return sendError(response, exc) finally: Session.close() log.debug('[delete_all] done')
def samlcheck(self): ''' This function is used to validate the username and the otp value/password in a SAML environment. If ``linotp.allowSamlAttributes = True`` then the attributes of the authenticated users are also contained in the response. method: validate/samlcheck arguments: * user: username / loginname * pass: the password that consists of a possible fixes password component and the OTP value * realm: optional realm to match the user to a useridresolver returns: JSON response ''' try: opt = None param = request.params (ok, opt) = self._check(param) attributes = {} if True == ok: allowSAML = False try: allowSAML = getFromConfig("allowSamlAttributes") except: log.warning("[samlcheck] Calling controller samlcheck. But allowSamlAttributes is False.") if "True" == allowSAML: ## Now we get the attributes of the user user = getUserFromParam(param) (uid, resId, resIdC) = getUserId(user) userInfo = getUserInfo(uid, resId, resIdC) log.debug("[samlcheck] getting attributes for: %s@%s" % (user.login, user.realm)) res = userInfo for key in ['username', 'surname', 'mobile', 'phone', 'givenname', 'email']: if key in res: attributes[key] = res[key] Session.commit() return sendResult(response, { 'auth': ok, 'attributes' : attributes } , 0, opt) except Exception as exx: log.exception("[samlcheck] validate/check failed: %r" % exx) Session.rollback() return sendResult(response, False, 0) finally: Session.close()
def pair(self): try: params = dict(**request.params) enc_response = params.get('pairing_response') if enc_response is None: raise Exception('Parameter missing') dec_response = decrypt_pairing_response(enc_response) if not dec_response.serial: raise ValidateError( 'Pairing responses with no serial attached ' 'are currently not implemented.') serial = dec_response.serial user_public_key = dec_response.user_public_key user_token_id = dec_response.user_token_id user = dec_response.user_login user = getUserFromParam(params, optional) # TODO: pairing policy tokens = getTokens4UserOrSerial(None, serial) if not tokens: raise Exception('Invalid serial in pairing response') if len(tokens) > 1: raise Exception('Multiple tokens found. Pairing not possible') token = tokens[0] if token.type != 'qr': raise Exception('Pairing is only implemented for the qrtoken') token.ensure_state('pairing_url_sent') token.addToTokenInfo('user_token_id', user_token_id) b64_user_public_key = b64encode(user_public_key) token.addToTokenInfo('user_public_key', b64_user_public_key) params['serial'] = serial params['user_public_key'] = user_public_key params['user_token_id'] = user_token_id params['user'] = user params['content_type'] = CONTENT_TYPE_PAIRING params['data'] = serial token.change_state('pairing_response_received') Session.commit() return sendResult(response, False) except Exception: Session.rollback() return sendResult(response, False, 0, status=False) finally: Session.close()
def pair(self): try: params = dict(**request.params) enc_response = params.get('pairing_response') if enc_response is None: raise Exception('Parameter missing') dec_response = decrypt_pairing_response(enc_response) if not dec_response.serial: raise ValidateError('Pairing responses with no serial attached ' 'are currently not implemented.') serial = dec_response.serial user_public_key = dec_response.user_public_key user_token_id = dec_response.user_token_id user = dec_response.user_login user = getUserFromParam(params, optional) # TODO: pairing policy tokens = getTokens4UserOrSerial(None, serial) if not tokens: raise Exception('Invalid serial in pairing response') if len(tokens) > 1: raise Exception('Multiple tokens found. Pairing not possible') token = tokens[0] if token.type != 'qr': raise Exception('Pairing is only implemented for the qrtoken') token.ensure_state('pairing_url_sent') token.addToTokenInfo('user_token_id', user_token_id) b64_user_public_key = b64encode(user_public_key) token.addToTokenInfo('user_public_key', b64_user_public_key) params['serial'] = serial params['user_public_key'] = user_public_key params['user_token_id'] = user_token_id params['user'] = user params['content_type'] = CONTENT_TYPE_PAIRING params['data'] = serial token.change_state('pairing_response_received') Session.commit() return sendResult(response, False) except Exception: Session.rollback() return sendResult(response, False, 0, status=False) finally: Session.close()
def delete_all(self): """ method: reporting/delete_all description: delete the reporting database table returns: dict in which value is the number of deleted rows exception: if an error occurs an exception is serialized and returned """ try: param = request.params request_realms = param.get('realms', '').split(',') status = param.get('status', ['total']) if status != ['total']: status = status.split(',') realm_whitelist = [] policies = getAdminPolicies('tokens', scope='monitoring') if policies['active'] and policies['realms']: realm_whitelist = policies.get('realms') # if there are no policies for us, we are allowed to see all realms if not realm_whitelist or '*' in realm_whitelist: realm_whitelist = request_context['Realms'].keys() realms = match_realms(request_realms, realm_whitelist) if '*' in status: status.remove('*') status.extend(['active', 'inactive', 'assigned', 'unassigned', 'active&assigned', 'active&unassigned', 'inactive&assigned', 'inactive&unassigned', 'total']) result = delete(realms=realms, status=status) Session.commit() return sendResult(response, result) except PolicyException as policy_exception: log.exception(policy_exception) Session.rollback() return sendError(response, unicode(policy_exception), 1) except Exception as exc: log.exception(exc) Session.rollback() return sendError(response, exc) finally: Session.close() log.debug('[delete_all] done')
def storeRealm(self): if self.name is None: self.name = '' self.name = self.name.lower() log.debug('storeRealm()') Session.add(self) Session.commit() log.debug('store realm success') return True
def check_status(self): """ check the status of a transaction - for polling support """ try: param = {} param.update(request.params) # # we require either state or transactionid as parameter transid = param.get('state', param.get('transactionid', None)) if not transid: raise ParameterError(_('Missing required parameter "state" or ' '"transactionid"!')) # # serial is an optional parameter serial = param.get('serial', None) # # but user is an required parameter if "user" not in param: raise ParameterError(_('Missing required parameter "serial"' ' or "user"!')) user = getUserFromParam(param) passw = param.get('pass', None) if passw is None: raise ParameterError(_('Missing required parameter "pass"!')) use_offline = param.get('use_offline', False) va = ValidationHandler() ok, opt = va.check_status(transid=transid, user=user, serial=serial, password=passw, use_offline=use_offline) c.audit['success'] = ok c.audit['info'] = unicode(opt) Session.commit() return sendResult(response, ok, 0, opt=opt) except Exception as exx: log.exception("check_status failed: %r" % exx) c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, 0) finally: Session.close()
def samlcheck(self): """ This function is used to validate the username and the otp value/password in a SAML environment. If ``linotp.allowSamlAttributes = True`` then the attributes of the authenticated users are also contained in the response. method: validate/samlcheck arguments: * user: username / loginname * pass: the password that consists of a possible fixes password component and the OTP value * realm: optional realm to match the user to a useridresolver returns: JSON response """ try: opt = None param = request.params (ok, opt) = self._check(param) attributes = {} if True == ok: allowSAML = False try: allowSAML = getFromConfig("allowSamlAttributes") except: log.warning("[samlcheck] Calling controller samlcheck. But allowSamlAttributes == False.") if "True" == allowSAML: ## Now we get the attributes of the user user = getUserFromParam(param, optional) (uid, resId, resIdC) = getUserId(user) userInfo = getUserInfo(uid, resId, resIdC) # users = getUserList({ 'username':user.getUser()} , user) log.debug("[samlcheck] getting attributes for: %s@%s" % (user.getUser(), user.getRealm())) res = userInfo for key in ["username", "surname", "mobile", "phone", "givenname", "email"]: if key in res: attributes[key] = res[key] Session.commit() return sendResult(response, {"auth": ok, "attributes": attributes}, 0, opt) except Exception as exx: log.error("[samlcheck] validate/check failed: %r" % exx) log.error("[samlcheck] %s" % traceback.format_exc()) Session.rollback() return sendError(response, "validate/samlcheck failed: %s" % unicode(exx), 0) finally: Session.close() log.debug("[samlcheck] done")
def check_t(self): param = {} value = {} ok = False opt = None try: param.update(request.params) passw = getParam(param, "pass", required) transid = param.get('state', None) if transid is not None: param['transactionid'] = transid del param['state'] if transid is None: transid = param.get('transactionid', None) if transid is None: raise Exception("missing parameter: state or transactionid!") vh = ValidationHandler() (ok, reply) = vh.check_by_transactionid(transid=transid, passw=passw, options=param) value['value'] = ok value['failcount'] = int(reply.get('failcount', 0)) c.audit['success'] = ok Session.commit() qr = param.get('qr', None) if qr and opt and 'message' in opt: try: dataobj = opt.get('message') param['alt'] = "%s" % opt if 'transactionid' in opt: param['transactionid'] = opt['transactionid'] return sendQRImageResult(response, dataobj, param) except Exception as exc: log.warning("failed to send QRImage: %r " % exc) return sendQRImageResult(response, opt, param) else: return sendResult(response, value, 1, opt=opt) except Exception as exx: log.exception("[check_t] validate/check_t failed: %r" % exx) c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, 0) finally: Session.close() log.debug('[check_t] done')
def check_t(self): param = {} value = {} ok = False opt = {} try: param.update(request.params) passw = getParam(param, "pass", required) transid = param.get('state', None) if transid is not None: param['transactionid'] = transid del param['state'] if transid is None: transid = param.get('transactionid', None) if transid is None: raise Exception("missing parameter: state or transactionid!") vh = ValidationHandler() (ok, opt) = vh.check_by_transactionid(transid=transid, passw=passw, options=param) value['value'] = ok value['failcount'] = int(opt.get('failcount', 0)) c.audit['success'] = ok Session.commit() qr = param.get('qr', None) if qr and opt and 'message' in opt: try: dataobj = opt.get('message') param['alt'] = "%s" % opt if 'transactionid' in opt: param['transactionid'] = opt['transactionid'] return sendQRImageResult(response, dataobj, param) except Exception as exc: log.warning("failed to send QRImage: %r " % exc) return sendQRImageResult(response, opt, param) else: return sendResult(response, value, 1, opt=opt) except Exception as exx: log.exception("[check_t] validate/check_t failed: %r" % exx) c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, 0) finally: Session.close() log.debug('[check_t] done')
def webkdc_validate(self): # Called by WebAuth via the Elm remctld scripts. # Verifies a one-time passcode and indicates how long # the token should be considered valid. param = {} try: param.update(request.params) username = param["user"] code = param["code"] user = User(username, "", "") th = TokenHandler() if ('token' in param): serial = param["token"] (ok, opt) = th.checkSerialPass(serial, code, options=None, user=user) else: (ok, opt) = th.checkUserPass(user, code) ret = { "success": ok, } if (ok): ret['expiration'] = round( time.time()) + 60 * 60, # one hour from now else: if opt == None: opt = {} ret['error'] = c.audit.get('info') log.error("[webkdc_validate] authorization failed: %s" % ret['error']) ret['code'] = -310 Session.commit() return sendResult(response, ret, 0, opt=opt) except Exception as exx: log.error("[webkdc_validate] validate/webkdc_validate failed: %r" % exx) log.error("[webkdc_validate] %s" % traceback.format_exc()) Session.rollback() return sendError( response, u"validate/webkdc_validate failed: %s" % unicode(exx), 0) finally: Session.close()
def storeToken(self): if self.LinOtpUserid is None: self.LinOtpUserid = u'' if self.LinOtpIdResClass is None: self.LinOtpIdResClass = '' if self.LinOtpIdResolver is None: self.LinOtpIdResolver = '' log.debug('storeToken()') Session.add(self) Session.flush() Session.commit() log.debug('store token success') return True
def setLogLevel(self): """ set the log level of a certain logger which is identified by the url parameter loggerName. example call: POST /maintenance/setLogLevel loggerName=linotp.lib.user level=10 (sets the log level of the user library to DEBUG) if loggerName is omitted, the root logger is assumed. """ # we check if the client cert was valid by looking for # the existance of an env variable. for apache this is # SSL_CLIENT_S_DN_CN. to support other servers we read # the name of the variable from the config env_var = getFromConfig('maintenance_verify_client_env_var', False) if env_var: client_cert = request.environ.get(env_var) if client_cert is None: abort(401) # ---------------------------------------------------------------------- # if no logger name is supplied we default to '' (which translates # to the root logger in the python stdlib logging api) name = request.POST.get('loggerName', '') # ---------------------------------------------------------------------- level_as_str = request.POST.get('level', '') if not level_as_str.isdigit(): abort(400) level = int(level_as_str) # ---------------------------------------------------------------------- set_logging_level(name, level) Session.commit()
def check_status(self): """ check the status of a transaction - for polling support """ param = {} ok = False opt = None try: param.update(request.params) transid = param.get('state', param.get('transactionid', None)) if not transid: raise ParameterError(_('Missing required parameter "state" or ' '"transactionid"!')) serial = param.get('serial', None) user = getUserFromParam(param, False) if not user and not serial: raise ParameterError(_('Missing required parameter "serial"' ' or "user"!')) passw = param.get('pass', None) if not passw: raise ParameterError(_('Missing required parameter "pass"!')) use_offline = param.get('use_offline', False) va = ValidationHandler() ok, opt = va.check_status(transid=transid, user=user, serial=serial, password=passw, use_offline=use_offline) c.audit['success'] = ok c.audit['info'] = unicode(opt) Session.commit() return sendResult(response, ok, 0, opt=opt) except Exception as exx: log.exception("check_status failed: %r" % exx) c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, 0) finally: Session.close() log.debug('[check] done')
def storeToken(self): log.debug('storeToken()') if self.LinOtpUserid is None: self.LinOtpUserid = u'' if self.LinOtpTokenDesc is None: self.LinOtpTokenDesc = u'' if self.LinOtpTokenInfo is None: self.LinOtpTokenInfo = u'' Session.add(self) Session.flush() Session.commit() log.debug('store token success') return True
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 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 webkdc_validate(self): # Called by WebAuth via the Elm remctld scripts. # Verifies a one-time passcode and indicates how long # the token should be considered valid. param = {} try: param.update(request.params) username = param["user"] code = param["code"] user = User(username, "", "") th = TokenHandler() if ('token' in param): serial = param["token"] (ok, opt) = th.checkSerialPass(serial, code, options = None, user=user) else: (ok, opt) = th.checkUserPass(user, code) ret = { "success" : ok, } if (ok): ret['expiration'] = round(time.time()) + 60 * 60, # one hour from now else: if opt == None: opt = {} ret['error'] = c.audit.get('info') log.error("[webkdc_validate] authorization failed: %s" % ret['error']) ret['code'] = -310 Session.commit() return sendResult(response, ret, 0, opt=opt) except Exception as exx: log.error("[webkdc_validate] validate/webkdc_validate failed: %r" % exx) log.error("[webkdc_validate] %s" % traceback.format_exc()) Session.rollback() return sendError(response, u"validate/webkdc_validate failed: %s" % unicode(exx), 0) finally: Session.close()
def save(self): ''' enforce the saveing of a challenge - will guarentee the uniqness of the transaction id :return: transaction id of the stored challeng ''' log.debug('[save] save challenge') try: Session.add(self) Session.commit() log.debug('save challenge : success') except Exception as exce: log.exception('[save]Error during saving challenge: %r' % exce) return self.transid
def __after__(self, action): """ """ try: c.audit['administrator'] = getUserFromRequest(request).get('login') audit.log(c.audit) Session.commit() return request except Exception as exception: log.exception(exception) Session.rollback() return sendError(response, exception, context='after') finally: Session.close()
def save(self): ''' enforce the saving of a challenge - will guarantee the uniqness of the transaction id :return: transaction id of the stored challenge ''' log.debug('[save] save challenge') try: Session.add(self) Session.commit() log.debug('save challenge : success') except Exception as exce: log.exception('[save]Error during saving challenge: %r' % exce) return self.transid
def check_url(self): ''' This function works with pam_url. ''' ok = False param = {} try: param.update(request.params) try: (ok, opt) = self._check(param) except AuthorizeException as acc: log.warning( "[check_url] authorization failed for validate/check_url: %r" % acc) c.audit['success'] = False c.audit['action_detail'] = unicode(acc) ok = False Session.commit() response.headers['blablafoo'] = 'application/json' ## TODO: this code seems not to be finished if not ok: abort(403) else: return "Preshared Key Todo" except webob.exc.HTTPUnauthorized as acc: ## the exception, when an abort() is called if forwarded log.error("[__before__::%r] webob.exception %r" % acc) log.error("[__before__] %s" % traceback.format_exc()) Session.rollback() raise acc except Exception as exx: log.error("[check_url] validate/check_url failed: %r" % exx) log.error("[check_url] %s" % traceback.format_exc()) Session.rollback() return sendError(response, u"validate/check_url failed: %s" % unicode(exx), 0) finally: Session.close() log.debug("[check_url] 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 delete_before(self): """ method: reporting/delete_before description: delete all entries from reporting database which are older than date date must be given in format: 'yyyy-mm-dd' returns: dict in which value is the number of deleted rows exception: if an error occurs an exception is serialized and returned """ try: param = request.params border_day = param.get('date') # this may throw ValueError if date is in wrong format datetime.strptime(border_day, "%Y-%m-%d") result = delete_before(border_day) Session.commit() return sendResult(response, result) except PolicyException as policy_exception: log.exception(policy_exception) Session.rollback() return sendError(response, unicode(policy_exception), 1) except ValueError as value_error: log.exception(value_error) Session.rollback() return sendError(response, unicode(value_error), 1) except Exception as exc: log.exception(exc) Session.rollback() return sendError(response, exc) finally: Session.close() log.debug('[tokens] done')
def check_url(self): ''' This function works with pam_url. ''' ok = False param = {} try: param.update(request.params) try: (ok, opt) = self._check(param) except AuthorizeException as acc: log.warning("[check_url] authorization failed for validate/check_url: %r" % acc) c.audit['success'] = False c.audit['action_detail'] = unicode(acc) ok = False Session.commit() response.headers['blablafoo'] = 'application/json' ## TODO: this code seems not to be finished if not ok: abort(403) else: return "Preshared Key Todo" except webob.exc.HTTPUnauthorized as acc: ## the exception, when an abort() is called if forwarded log.error("[__before__::%r] webob.exception %r" % acc) log.error("[__before__] %s" % traceback.format_exc()) Session.rollback() raise acc except Exception as exx: log.error("[check_url] validate/check_url failed: %r" % exx) log.error("[check_url] %s" % traceback.format_exc()) Session.rollback() return sendError(response, u"validate/check_url failed: %s" % unicode(exx), 0) finally: Session.close() log.debug("[check_url] done")
def autosms(self): ''' This function is used to test the autosms policy method: testing/autosms arguments: user - username / loginname realm - additional realm to match the user to a useridresolver returns: JSON response ''' log.debug('[autosms]') param = request.params try: if isSelfTest() == False: Session.rollback() return sendError( response, "The testing controller can only be used in SelfTest mode!", 0) user = getUserFromParam(param, required) ok = get_auth_AutoSMSPolicy() Session.commit() return sendResult(response, ok, 0) except Exception as e: log.error("[autosms] validate/check failed: %r", e) log.error("[autosms] %s" % traceback.format_exc()) Session.rollback() return sendError(response, "validate/check failed:" + unicode(e), 0) finally: Session.close() log.debug('[autosms] done')
def help(self): ''' This downloads the Manual The filename will be the 3. part,ID https://172.16.200.6/manage/help/somehelp.pdf The file is downloaded through pylons! ''' try: directory = config.get("linotpManual.Directory", "/usr/share/doc/linotp") default_filename = config.get("linotpManual.File", "LinOTP_Manual-en.pdf") headers = [] route_dict = request.environ.get('pylons.routes_dict') filename = route_dict.get('id') if not filename: filename = default_filename + ".gz" headers = [ ('content-Disposition', 'attachment; filename=\"' + default_filename + '\"'), ('content-Type', 'application/x-gzip') ] from paste.fileapp import FileApp wsgi_app = FileApp("%s/%s" % (directory, filename), headers=headers) Session.commit() return wsgi_app(request.environ, self.start_response) except Exception as e: log.error("[help] Error loading helpfile: %r" % e) log.error("[help] %s" % traceback.format_exc()) Session.rollback() return sendError(response, e) finally: Session.close() log.debug("[help] done")
def setup_app(conf, conf_global=None, unitTest=False): ''' setup_app is the hook, which is called, when the application is created :param conf: the application configuration :return: - nothing - ''' if conf_global is not None: if conf_global.has_key("sqlalchemy.url"): log.info("sqlalchemy.url") else: conf.get("sqlalchemy.url", None) if unitTest is True: log.info("Deleting previous tables...") meta.metadata.drop_all(bind=meta.engine) # Create the tables if they don't already exist log.info("Creating tables...") meta.metadata.create_all(bind=meta.engine) if conf.has_key("linotpSecretFile"): filename = conf.get("linotpSecretFile") try: with open(filename): pass except IOError: log.warning("The Linotp Secret File could not be found " + "-creating a new one: %s" % filename) f_handle = open(filename, 'ab+') secret = os.urandom(32 * 5) f_handle.write(secret) f_handle.close() os.chmod(filename, 0400) log.info("linotpSecretFile: %s" % filename) set_defaults() Session.commit() log.info("Successfully set up.")
def autosms(self): ''' This function is used to test the autosms policy method: testing/autosms arguments: user - username / loginname realm - additional realm to match the user to a useridresolver returns: JSON response ''' param = request.params try: if isSelfTest() is False: Session.rollback() return sendError( response, "The testing controller can only be used in SelfTest mode!", 0) if "user" not in param: raise ParameterError("Missing parameter: 'user'") ok = get_auth_AutoSMSPolicy() Session.commit() return sendResult(response, ok, 0) except Exception as e: log.exception("[autosms] validate/check failed: %r", e) Session.rollback() return sendError(response, "validate/check failed:" + unicode(e), 0) finally: Session.close()
def setup_app(conf, conf_global=None, unitTest=False): ''' setup_app is the hook, which is called, when the application is created :param conf: the application configuration :return: - nothing - ''' if conf_global is not None: if conf_global.has_key("sqlalchemy.url"): log.info("sqlalchemy.url") else: conf.get("sqlalchemy.url", None) if unitTest is True: log.info("Deleting previous tables...") meta.metadata.drop_all(bind=meta.engine) ## Create the tables if they don't already exist log.info("Creating tables...") meta.metadata.create_all(bind=meta.engine) if conf.has_key("linotpSecretFile"): filename = conf.get("linotpSecretFile") try: with open(filename): pass except IOError: log.warning("The Linotp Secret File could not be found " + "-creating a new one: %s" % filename) f_handle = open(filename, 'ab+') secret = os.urandom(32 * 5) f_handle.write(secret) f_handle.close() os.chmod(filename, 0400) log.info("linotpSecretFile: %s" % filename) set_defaults() Session.commit() log.info("Successfully set up.")
def __after__(self, action): """ """ params = {} try: params.update(request.params) c.audit['administrator'] = getUserFromRequest(request).get('login') audit.log(c.audit) Session.commit() return request except Exception as exception: log.exception(exception) Session.rollback() return sendError(response, exception, context='after') finally: Session.close() log.debug('[__after__] done')
def autosms(self): ''' This function is used to test the autosms policy method: testing/autosms arguments: user - username / loginname realm - additional realm to match the user to a useridresolver returns: JSON response ''' log.debug('[autosms]') param = request.params try: if isSelfTest() == False: Session.rollback() return sendError(response, "The testing controller can only be used in SelfTest mode!", 0) user = getUserFromParam(param, required) ok = get_auth_AutoSMSPolicy() Session.commit() return sendResult(response, ok, 0) except Exception as e: log.error("[autosms] validate/check failed: %r", e) log.error("[autosms] %s" % traceback.format_exc()) Session.rollback() return sendError(response, "validate/check failed:" + unicode(e), 0) finally: Session.close() log.debug('[autosms] done')
def help(self): """ This downloads the Manual The filename will be the 3. part,ID https://172.16.200.6/manage/help/somehelp.pdf The file is downloaded through pylons! """ try: directory = config.get("linotpManual.Directory", "/usr/share/doc/linotp") default_filename = config.get("linotpManual.File", "LinOTP_Manual-en.pdf") headers = [] route_dict = request.environ.get("pylons.routes_dict") filename = route_dict.get("id") if not filename: filename = default_filename + ".gz" headers = [ ("content-Disposition", 'attachment; filename="' + default_filename + '"'), ("content-Type", "application/x-gzip"), ] from paste.fileapp import FileApp wsgi_app = FileApp("%s/%s" % (directory, filename), headers=headers) Session.commit() return wsgi_app(request.environ, self.start_response) except Exception as e: log.error("[help] Error loading helpfile: %r" % e) log.error("[help] %s" % traceback.format_exc()) Session.rollback() return sendError(response, e) finally: Session.close() log.debug("[help] done")
def webkdc_userinfo(self): # Called by WebAuth via the Elm remctld scripts. # Returns information about whether the user owns any tokens. # TODO: Require some sort of session token. param = {} try: param.update(request.params) user = getUserFromParam(param, optionalOrRequired=True) if (user is not None and user.isEmpty() == False): (userid, idResolver, idResolverClass) = getUserId(user) sqlQuery = Session.query( model.Token).with_lockmode("update").filter( model.Token.LinOtpUserid == userid).filter( model.Token.LinOtpIdResClass == idResolverClass ).filter(model.Token.LinOtpIsactive == True) tokenList = {} for token in sqlQuery: tokenList[token.LinOtpTokenSerialnumber] = json.loads( token.LinOtpTokenInfo) Session.commit() return sendResult(response, tokenList, 0) except Exception as exx: log.error("[webkdc_userinfo] validate/webkdc_userinfo failed: %r" % exx) log.error("[webkdc_userinfo] %s" % traceback.format_exc()) Session.rollback() return sendError( response, u"validate/webkdc_userinfo failed: %s" % unicode(exx), 0) finally: Session.close()
def userinfo(self): """ method: monitoring/userinfo description: for each realm, display the resolvers and the number of users per resolver arguments: * realms - optional: takes a realm, only information on this realm will be displayed returns: a json result with: { "head": [], "data": [ [row1], [row2] .. ] } """ result = {} try: param = request.params request_realms = param.get('realms', '').split(',') monit_handler = MonitorHandler() policies = getAdminPolicies('userinfo', scope='monitoring') realm_whitelist = [] if policies['active'] and policies['realms']: realm_whitelist = policies.get('realms') # if there are no policies for us, we are allowed to see all realms if not realm_whitelist or '*' in realm_whitelist: realm_whitelist = request_context['Realms'].keys() realms = match_realms(request_realms, realm_whitelist) realm_info = {} for a_realm in realms: realm_info[a_realm] = monit_handler.resolverinfo(a_realm) result[_('Realms')] = realm_info Session.commit() return sendResult(response, result) except PolicyException as policy_exception: log.exception(policy_exception) Session.rollback() return sendError(response, unicode(policy_exception), 1) except Exception as exc: log.exception(exc) Session.rollback() return sendError(response, exc) finally: Session.close() log.debug('[resolvers] done')
def tokens(self): """ method: monitoring/tokens description: Displays the number of tokens (with status) per realm (one token might be in multiple realms). The Summary gives the sum of all tokens in all given realms and might be smaller than the summ of all tokens as tokens which have two realms are only counted once! arguments: * status - optional: takes assigned or unassigned, give the number of tokens with this characteristic * realms - optional: takes realms, only the number of tokens in these realms will be displayed returns: a json result with: { "head": [], "data": [ [row1], [row2] .. ] } exception: if an error occurs an exception is serialized and returned """ result = {} try: param = request.params status = param.get('status', ['total']) if status != ['total']: status = status.split(',') status.append('total') request_realms = param.get('realms', '').split(',') monit_handler = MonitorHandler() realm_whitelist = [] policies = getAdminPolicies('tokens', scope='monitoring') if policies['active'] and policies['realms']: realm_whitelist = policies.get('realms') # if there are no policies for us, we are allowed to see all realms if not realm_whitelist or '*' in realm_whitelist: realm_whitelist = request_context['Realms'].keys() realms = match_realms(request_realms, realm_whitelist) realm_info = {} for a_realm in realms: token_count = monit_handler.token_count([a_realm], status) realm_info[a_realm] = token_count result[_('Summary')] = monit_handler.token_count(realms, status) result[_('Realms')] = realm_info Session.commit() return sendResult(response, result) except PolicyException as policy_exception: log.exception(policy_exception) Session.rollback() return sendError(response, unicode(policy_exception), 1) except Exception as exc: log.exception(exc) Session.rollback() return sendError(response, exc) finally: Session.close() log.debug('[tokens] done')
def pair(self): """ validate/pair: for the enrollment of qr and push token """ try: # -------------------------------------------------------------- -- params = dict(**request.params) enc_response = params.get('pairing_response') if enc_response is None: raise Exception('Parameter missing') # -------------------------------------------------------------- -- dec_response = decrypt_pairing_response(enc_response) token_type = dec_response.token_type pairing_data = dec_response.pairing_data if not hasattr(pairing_data, 'serial') or \ pairing_data.serial is None: raise ValidateError('Pairing responses with no serial attached' ' are currently not implemented.') # --------------------------------------------------------------- - # TODO: pairing policy tokens = getTokens4UserOrSerial(None, pairing_data.serial) if not tokens: raise Exception('Invalid serial in pairing response') if len(tokens) > 1: raise Exception('Multiple tokens found. Pairing not possible') token = tokens[0] # prepare some audit entries t_owner = token.getUser() realms = token.getRealms() realm = '' if realms: realm = realms[0] c.audit['user'] = t_owner or '' c.audit['realm'] = realm # --------------------------------------------------------------- -- if token.type != token_type: raise Exception('Serial in pairing response doesn\'t match ' 'supplied token_type') # --------------------------------------------------------------- -- token.pair(pairing_data) c.audit['success'] = 1 Session.commit() return sendResult(response, False) # ------------------------------------------------------------------- -- except Exception as exx: log.exception("validate/pair failed: %r" % exx) c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, 0, status=False) finally: Session.close()
def smspin(self): ''' This function is used in conjunction with an SMS token: the user authenticates with user and pin (pass) and will receive on his mobile an OTP as message method: validate/smspin arguments: * user: username / loginname * pass: the password that consists of a possible fixed password * realm: additional realm to match the user to a useridresolver returns: JSON response ''' ret = False param = request.params state = '' message = 'No sms message defined!' try: user = getUserFromParam(param, optional) c.audit['user'] = user.login c.audit['realm'] = user.realm or getDefaultRealm() c.audit['success'] = 0 (ret, opt) = self._check(param) ## here we build some backward compatibility if type(opt) is dict: state = opt.get('state', '') or '' message = opt.get('message', '') or 'No sms message defined!' # sucessfull submit if (message in ['sms with otp already submitted', 'sms submitted'] and len(state) > 0): ret = True c.audit['success'] = 1 # sending sms failed should be an error elif message in ['sending sms failed']: ret = True c.audit['success'] = 0 # anything else is an exception else: raise Exception(message) Session.commit() return sendResult(response, ret, opt) except Exception as exx: log.exception("[smspin] validate/smspin failed: %r" % exx) # If an internal error occurs or the SMS gateway did not send # the SMS, we write this to the detail info. c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, 0) finally: Session.close() log.debug("[smspin] done")
def simplecheck(self): ''' This function is used to validate the username and the otp value/password. method: validate/simplecheck arguments: * user: username / loginname * pass: the password that consists of a possible fixes password component and the OTP value * realm: additional realm to match the user to a useridresolver returns: Simple ascii response: :-) in case of success :-( in case of failed authentication :-/ in case of any error ''' opt = None param = request.params res = [] try: try: (ok, opt) = self._check(param) except AuthorizeException as e: log.warning("[simplecheck] validate/simplecheck: %r" % e) c.audit['success'] = False c.audit['action_detail'] = unicode(e) ok = False Session.commit() if ok is True: ret = u":-)" else: ret = u":-(" res.append(ret) if opt is not None: if 'state' in opt or 'transactionid' in opt: stat = opt.get('transactionid') or opt.get('state') res.append(stat) if "data" in opt or "message" in opt: msg = opt.get('data') or opt.get('message') res.append(msg) return " ".join(res).strip() except Exception as exx: log.exception("[simplecheck] failed: %r" % exx) Session.rollback() return u":-(" finally: Session.close() log.debug('[simplecheck] done')
def load_form(self): ''' This shows the enrollment form for a requested token type. implicit parameters are: :param type: token type :param scope: defines the rendering scope :return: rendered html of the requested token ''' res = '' param = {} try: param.update(request.params) act = getParam(param, "type", required) try: (tok, section, scope) = act.split('.') except Exception: return res if section != 'selfservice': return res g = config['pylons.app_globals'] tokenclasses = copy.deepcopy(g.tokenclasses) if tok in tokenclasses: tclass = tokenclasses.get(tok) tclt = newToken(tclass) if hasattr(tclt, 'getClassInfo'): sections = tclt.getClassInfo(section, {}) if scope in sections.keys(): section = sections.get(scope) page = section.get('page') c.scope = page.get('scope') c.authUser = self.authUser html = page.get('html') res = render(os.path.sep + html) res = remove_empty_lines(res) Session.commit() return res except CompileException as exx: log.exception("[load_form] compile error while processing %r.%r:" % (tok, scope)) log.error("[load_form] %r" % exx) Session.rollback() raise Exception(exx) except Exception as exx: Session.rollback() error = ('error (%r) accessing form data for: tok:%r, scope:%r' ', section:%r' % (exx, tok, scope, section)) log.exception(error) return '<pre>%s</pre>' % error finally: Session.close() log.debug('[load_form] done')
def check(self): ''' This function is used to validate the username and the otp value/password. method: validate/check arguments: * user: The username or loginname * pass: The password that consist of a possible fixed password component and the OTP value * realm (optional): An optional realm to match the user to a useridresolver * challenge (optional): optional challenge + otp verification for challenge response token. This indicates, that tis request is a challenge request. * data (optional): optional challenge + otp verification for challenge response token. This indicates, that tis request is a challenge request. * state (optional): The optional id to respond to a previous challenge. * transactionid (optional): The optional id to respond to a previous challenge. returns: JSON response:: { "version": "LinOTP 2.4", "jsonrpc": "2.0", "result": { "status": true, "value": false }, "id": 0 } If ``status`` is ``true`` the request was handled successfully. If ``value`` is ``true`` the user was authenticated successfully. ''' param = {} ok = False opt = None try: param.update(request.params) # prevent the detection if a user exist # by sending a request w.o. pass parameter try: (ok, opt) = self._check(param) except (AuthorizeException, ParameterError) as exx: log.warning( "[check] authorization failed for validate/check: %r" % exx) c.audit['success'] = False c.audit['info'] = unicode(exx) ok = False if is_auth_return(ok): if opt is None: opt = {} opt['error'] = c.audit.get('info') Session.commit() qr = param.get('qr', None) if qr and opt and 'message' in opt: try: dataobj = opt.get('message') param['alt'] = "%s" % opt if 'transactionid' in opt: param['transactionid'] = opt['transactionid'] return sendQRImageResult(response, dataobj, param) except Exception as exc: log.warning("failed to send QRImage: %r " % exc) return sendQRImageResult(response, opt, param) else: return sendResult(response, ok, 0, opt=opt) except Exception as exx: log.exception("[check] validate/check failed: %r" % exx) # If an internal error occurs or the SMS gateway did not send the SMS, we write this to the detail info. c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, 0) finally: Session.close() log.debug('[check] 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 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 check(self): ''' This function is used to login method: openid/check arguments: user - user to login realm - in which realm the user should login pass - password returns: JSON response ''' ok = False param = {} do_redirect = None message = None try: param.update(request.params) same_user = True passw = getParam(param, "pass", optional) ## getUserFromParam will return default realm if no realm is ## provided via @ append or extra parameter realm ## if the provided realm does not exist, the realm is left empty user = getUserFromParam(param, optional) ## if the requested user has a realm specified (via @realm append) ## and this is not the same as the user from getUserFromParam ## the requested user is not a valid one! p_user = param.get('user', '') if "@" in p_user: if p_user != "%s@%s" % (user.login, user.realm): same_user = False c.audit['user'] = user.login c.audit['realm'] = user.realm or getDefaultRealm() vh = ValidationHandler() if same_user is True: (ok, opt) = vh.checkUserPass(user, passw) c.audit['success'] = ok if ok: ## if the user authenticated successfully we need to set the cookie aka ## the ticket and we need to remember this ticket. user = "******" % (user.login, c.audit['realm']) log.debug("[check] user=%s" % user) token = self.storage.set_user_token(user, expire=self.COOKIE_EXPIRE) log.debug("[check] token=%s" % token) cookie = "%s:%s" % (user, token) log.debug("[check] cookie=%s" % cookie) response.set_cookie(COOKIE_NAME, cookie, max_age=self.COOKIE_EXPIRE) else: message = "Your login attempt was not successful!" Session.commit() # Only if we logged in successfully we redirect to the original # page (Servive Provider). Otherwise we will redirect to the # status page p = {} redirect_to = getParam(param, "redirect_to", optional) if redirect_to and ok: p = {} for k in [ 'openid.return_to', "openid.realm", "openid.ns", "openid.claimed_id", "openid.mode", "openid.identity" ]: p[k] = param[k] else: if message is not None: p["message"] = message redirect_to = "/openid/status" do_redirect = url(str("%s?%s" % (redirect_to, urlencode(p)))) except Exception as exx: log.exception("[check] openid/check failed: %r" % exx) Session.rollback() return sendError(response, "openid/check failed: %r" % exx, 0) finally: Session.close() log.debug('[check] done') if do_redirect: log.debug("[check] now redirecting to %s" % do_redirect) redirect(do_redirect)
def check_s(self): ''' This function is used to validate the serial and the otp value/password. method: validate/check_s arguments: * serial: the serial number of the token * pass: the password that consists of a possible fixes password component and the OTP value returns: JSON response ''' param = {} param.update(request.params) options = {} options.update(param) for k in ['user', 'serial', "pass", "init"]: if k in options: del options[k] if 'init' in param: if isSelfTest() is True: options['initTime'] = param.get('init') try: passw = getParam(param, "pass", optional) serial = getParam(param, 'serial', optional) if serial is None: user = getParam(param, 'user', optional) if user is not None: user = getUserFromParam(param, optional) toks = getTokens4UserOrSerial(user=user) if len(toks) == 0: raise Exception("No token found!") elif len(toks) > 1: raise Exception("More than one token found!") else: tok = toks[0].token desc = tok.get() realms = desc.get('LinOtp.RealmNames') if realms is None or len(realms) == 0: realm = getDefaultRealm() elif len(realms) > 0: realm = realms[0] userInfo = getUserInfo(tok.LinOtpUserid, tok.LinOtpIdResolver, tok.LinOtpIdResClass) user = User(login=userInfo.get('username'), realm=realm) serial = tok.getSerial() c.audit['serial'] = serial if isSelfTest() is True: initTime = getParam(param, "init", optional) if initTime is not None: if options is None: options = {} options['initTime'] = initTime options['scope'] = {"check_s": True} vh = ValidationHandler() (ok, opt) = vh.checkSerialPass(serial, passw, options=options) c.audit['success'] = ok Session.commit() qr = param.get('qr', None) if qr and opt and 'message' in opt: try: dataobj = opt.get('message') param['alt'] = "%s" % opt if 'transactionid' in opt: param['transactionid'] = opt['transactionid'] return sendQRImageResult(response, dataobj, param) except Exception as exc: log.warning("failed to send QRImage: %r " % exc) return sendQRImageResult(response, opt, param) else: return sendResult(response, ok, 0, opt=opt) except Exception as exx: log.exception("[check_s] validate/check_s failed: %r" % exx) c.audit['info'] = unicode(exx) Session.rollback() return sendResult(response, False, id=0, status=False) finally: Session.close() log.debug('[check_s] 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', {}) # 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 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 check(self): ''' This function is used to login method: openid/check arguments: user - user to login realm - in which realm the user should login pass - password returns: JSON response ''' ok = False param = {} do_redirect = None message = None try: param.update(request.params) same_user = True passw = getParam(param, "pass", optional) ## getUserFromParam will return default realm if no realm is ## provided via @ append or extra parameter realm ## if the provided realm does not exist, the realm is left empty user = getUserFromParam(param, optional) ## if the requested user has a realm specified (via @realm append) ## and this is not the same as the user from getUserFromParam ## the requested user is not a valid one! p_user = param.get('user', '') if "@" in p_user: if p_user != "%s@%s" % (user.login, user.realm): same_user = False c.audit['user'] = user.login c.audit['realm'] = user.realm or getDefaultRealm() if same_user is True: (ok, opt) = checkUserPass(user, passw) c.audit['success'] = ok if ok: ## if the user authenticated successfully we need to set the cookie aka ## the ticket and we need to remember this ticket. user = "******" % (user.login, c.audit['realm']) log.debug("[check] user=%s" % user) token = self.storage.set_user_token(user, expire=self.COOKIE_EXPIRE) log.debug("[check] token=%s" % token) cookie = "%s:%s" % (user, token) log.debug("[check] cookie=%s" % cookie) response.set_cookie(COOKIE_NAME, cookie, max_age=self.COOKIE_EXPIRE) else: message = "Your login attempt was not successful!" Session.commit() # Only if we logged in successfully we redirect to the original # page (Servive Provider). Otherwise we will redirect to the # status page p = {} redirect_to = getParam(param, "redirect_to", optional) if redirect_to and ok: p = {} for k in [ 'openid.return_to', "openid.realm", "openid.ns", "openid.claimed_id", "openid.mode", "openid.identity" ]: p[k] = param[k] else: if message is not None: p["message"] = message redirect_to = "/openid/status" do_redirect = url(str("%s?%s" % (redirect_to, urlencode(p)))) except Exception as exx: log.error("[check] openid/check failed: %r" % exx) log.error("[__before__] %s" % traceback.format_exc()) Session.rollback() return sendError(response, "openid/check failed: %r" % exx, 0) finally: Session.close() log.debug('[check] done') if do_redirect: log.debug("[check] now redirecting to %s" % do_redirect) redirect(do_redirect)
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')