# -*- coding: utf-8 -*-
#
# LinOTP - the open source solution for two factor authentication
# Copyright (C) 2010 - 2014 LSE Leading Security Experts GmbH
#
# This file is part of LinOTP server.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public
# License, version 3, as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the
# GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# E-mail: linotp@lsexperts.de
# Contact: www.linotp.org
# Support: www.lsexperts.de
#
"""
gettoken controller - to retrieve OTP values
"""
import logging
from pylons import tmpl_context as c
from pylons import request, response
from pylons import config
from pylons.templating import render_mako as render
from linotp.lib.base import BaseController
from linotp.lib.util import getParam, check_session
from linotp.lib.util import get_client
from linotp.lib.user import getUserFromParam
from linotp.lib.user import getDefaultRealm
from linotp.lib.user import getUserFromRequest
from linotp.lib.token import getTokenType, getOtp, get_multi_otp, getTokens4UserOrSerial
from linotp.lib.policy import checkPolicyPre, PolicyException
from linotp.lib.reply import sendResult, sendError
from linotp.model.meta import Session
import traceback
audit = config.get('audit')
optional = True
required = False
log = logging.getLogger(__name__)
[docs]class GettokenController(BaseController):
'''
The linotp.controllers are the implementation of the web-API to talk to the LinOTP server.
The ValidateController is used to validate the username with its given OTP value.
The Tagespasswort Token uses this controller to retrieve the current OTP value of
the Token and be able to set it in the application
The functions of the GettokenController are invoked like this
https://server/gettoken/<functionname>
The functions are described below in more detail.
'''
def __before__(self, action, **params):
log.debug("[__before__]")
try:
audit.initialize()
c.audit['client'] = get_client()
check_session()
except Exception as exx:
log.error("[__before__::%r] exception %r" % (action, exx))
log.error("[__before__] %s" % traceback.format_exc())
Session.rollback()
Session.close()
return sendError(response, exx, context='before')
finally:
log.debug("[__before__::%r] done" % (action))
def __after__(self):
c.audit['administrator'] = getUserFromRequest(request).get("login")
if request.params.has_key('serial'):
c.audit['serial'] = request.params['serial']
c.audit['token_type'] = getTokenType(request.params['serial'])
audit.log(c.audit)
[docs] 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")
[docs] 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')
#eof###########################################################################