"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "linotpd/src/linotp/controllers/userservice.py" between
LinOTP-release-2.11.2.tar.gz and LinOTP-release-2.12.tar.gz

About: LinOTP is a flexible and versatile OTP-platform for strong user authentication (two-factor authentication with one time passwords).

userservice.py  (LinOTP-release-2.11.2):userservice.py  (LinOTP-release-2.12)
skipping to change at line 59 skipping to change at line 59
import base64 import base64
import logging import logging
import os import os
try: try:
import json import json
except ImportError: except ImportError:
import simplejson as json import simplejson as json
import webob
from pylons import request from pylons import request
from pylons import response from pylons import response
from pylons import config from pylons import config
from pylons import tmpl_context as c from pylons import tmpl_context as c
from pylons.controllers.util import abort from pylons.controllers.util import abort
from pylons.templating import render_mako as render from pylons.templating import render_mako as render
from mako.exceptions import CompileException from mako.exceptions import CompileException
from linotp.lib.base import BaseController from linotp.lib.base import BaseController
from linotp.lib.auth.validate import ValidationHandler from linotp.lib.auth.validate import ValidationHandler
from linotp.lib.challenges import Challenges
from linotp.lib.policy import (checkPolicyPre, from linotp.lib.policy import (checkPolicyPre,
checkPolicyPost, checkPolicyPost,
PolicyException, PolicyException,
getOTPPINEncrypt, getOTPPINEncrypt,
checkOTPPINPolicy, checkOTPPINPolicy,
get_client_policy, get_client_policy,
) )
from linotp.lib.reply import (sendResult, from linotp.lib.reply import (sendResult,
skipping to change at line 518 skipping to change at line 521
c.audit['success'] = False c.audit['success'] = False
Session.rollback() Session.rollback()
return sendError(response, exx) return sendError(response, exx)
finally: finally:
Session.close() Session.close()
def _login_with_cookie(self, cookie, params): def _login_with_cookie(self, cookie, params):
""" """
verify the mfa login second step
- the credentials have been verified in the first step, so that the
authentication state is either 'credentials_verified' or
'challenge_triggered'
if credentials are already verified, the state of authenticaion :param cookie: preserving the authentication state
is stored in the cookie cache
:param cookie: the authentication state
:param params: the request parameters :param params: the request parameters
""" """
user, _client, auth_state, state_data = get_cookie_authinfo(cookie) user, _client, auth_state, _state_data = get_cookie_authinfo(cookie)
if not user: if not user:
raise UserNotFound('no user info in authentication cache') raise UserNotFound('no user info in authentication cache')
request_context['selfservice'] = {
'state': auth_state,
'user': user
}
if auth_state == 'credentials_verified': if auth_state == 'credentials_verified':
return self._login_with_cookie_credentials(cookie, params)
# TODO: finish implementation in checkUserPass / checkSerialPass: elif auth_state == 'challenge_triggered':
# the cookie and the path should be part of the request context return self._login_with_cookie_challenge(cookie, params)
# so that checkUserPass could skip the password check
# -------------------------------------------------------------- -- else:
raise NotImplementedError('unknown state %r' % auth_state)
otp = params.get('otp', '') def _login_with_cookie_credentials(self, cookie, params):
serial = params.get('serial') """
verify the mfa login second step
- the credentials have been verified in the first step, so that the
authentication state is 'credentials_verified'
vh = ValidationHandler() :param cookie: preserving the authentication state
if 'serial' in params: :param params: the request parameters
res, reply = vh.checkSerialPass(serial, passw=otp, """
options=params)
else:
request_context['selfservice'] = {'state': auth_state,
'user': user}
res, reply = vh.checkUserPass(user, passw=otp, options=params)
# -------------------------------------------------------------- -- user, _client, _auth_state, _state_data = get_cookie_authinfo(cookie)
# if an otp is provided we can do a direct authentication # -------------------------------------------------------------- --
if otp: otp = params.get('otp', '')
if res: serial = params.get('serial')
(cookie, expires, _exp) = create_auth_cookie(
user, self.client)
response.set_cookie('user_selfservice', cookie,
secure=secure_cookie,
expires=expires)
c.audit['info'] = ("User %r authenticated from otp" % user) vh = ValidationHandler()
Session.commit() if 'serial' in params:
return sendResult(response, res, 0) res, reply = vh.checkSerialPass(
serial, passw=otp, options=params)
# -------------------------------------------------------------- -- else:
res, reply = vh.checkUserPass(user, passw=otp, options=params)
# if no otp is provided, we check if a challenge is triggered # -------------------------------------------------------------- --
c.audit['action_detail'] = ("User %r authenticated with " # if res is True: success for direct authentication and we can
"credentials_verified state" % # set the cookie for successful authenticated
user)
if not res and reply: if res:
ret = create_auth_cookie(user, self.client)
(cookie, expires, _exp) = ret
if 'message' in reply and "://chal/" in reply['message']: response.set_cookie('user_selfservice', cookie,
reply['img_src'] = create_img_src(reply['message']) secure=secure_cookie,
expires=expires)
(cookie, expires, c.audit['info'] = ("User %r authenticated from otp" % user)
expiration) = create_auth_cookie(
user, self.client,
state='challenge_triggered',
state_data=reply)
response.set_cookie('user_selfservice', cookie, Session.commit()
secure=secure_cookie, return sendResult(response, res, 0)
expires=expires)
c.audit['success'] = False # -------------------------------------------------------------- --
Session.commit() # if res is False and reply is provided, a challenge was triggered
return sendResult(response, False, 0, opt=reply) # and we set the state 'challenge_triggered'
Session.commit() if not res and reply:
return sendResult(response, res, 0, opt=reply)
# -------------------------------------------------------------- -- if 'message' in reply and "://chal/" in reply['message']:
reply['img_src'] = create_img_src(reply['message'])
elif auth_state == 'challenge_triggered': ret = create_auth_cookie(
user, self.client, state='challenge_triggered', state_data=reply
)
cookie, expires, expiration = ret
if params.get('otp'): response.set_cookie('user_selfservice', cookie,
# -------------------------------------------------------------- secure=secure_cookie,
-- expires=expires)
# if there has been a challenge triggerd before, we can extract c.audit['success'] = False
# the the transaction info from the cookie cached data
if not state_data: Session.commit()
raise Exception('invalid state data') return sendResult(response, False, 0, opt=reply)
# TODO: adjust the state_data for multiple challenges # -------------------------------------------------------------- --
transid = state_data.get('transactionid') # if no reply and res is False, the authentication failed
params['transactionid'] = transid
otp_value = params['otp'] if not res and not reply:
vh = ValidationHandler() Session.commit()
res, reply = vh.check_by_transactionid(transid, passw=otp_value, return sendResult(response, False, 0)
options=params)
c.audit['success'] = res def _login_with_cookie_challenge(self, cookie, params):
"""
verify the mfa login second step
- the credentials have been verified in the first step and a challenge
has been triggered, so that the authentication state is
'challenge_triggered'
if res: :param cookie: preserving the authentication state
(cookie, expires, :param params: the request parameters
expiration) = create_auth_cookie(user, self.client) """
user, _client, _auth_state, state_data = get_cookie_authinfo(cookie)
response.set_cookie('user_selfservice', cookie, if not state_data:
secure=secure_cookie, raise Exception('invalid state data')
expires=expires)
c.audit['action_detail'] = "expires: %s " % expiration # if there has been a challenge triggerd before, we can extract
c.audit['info'] = "%r logged in " % user # the the transaction info from the cookie cached data
Session.commit() transid = state_data.get('transactionid')
return sendResult(response, res, 0) _exp, challenges = Challenges.get_challenges(
transid=transid, filter_open=True)
if not challenges:
log.info("cannot login with challenge as challenges are expired!")
abort(401, _('challenge expired!'))
# -------------------------------------------------------------- -- if 'otp' in params:
# if there is no otp in the request, we assume that we params['transactionid'] = transid
# have to poll for the transaction state
if not state_data: otp_value = params['otp']
raise Exception('invalid state data')
verified = False vh = ValidationHandler()
transid = state_data.get('transactionid') res, _reply = vh.check_by_transactionid(
transid, passw=otp_value, options=params)
va = ValidationHandler() c.audit['success'] = res
ok, opt = va.check_status(transid=transid, user=user,
serial=None, password='passw',
)
if ok and opt and opt.get('transactions', {}).get(transid):
verified = opt.get(
'transactions', {}).get(
transid).get(
'valid_tan')
if verified: if res:
(cookie, expires, (cookie, expires,
expiration) = create_auth_cookie(user, self.client) expiration) = create_auth_cookie(user, self.client)
response.set_cookie('user_selfservice', cookie, response.set_cookie('user_selfservice', cookie,
secure=secure_cookie, secure=secure_cookie,
expires=expires) expires=expires)
c.audit['action_detail'] = "expires: %s " % expiration c.audit['action_detail'] = "expires: %s " % expiration
c.audit['info'] = "%r logged in " % user c.audit['info'] = "%r logged in " % user
Session.commit() Session.commit()
return sendResult(response, verified, 0) return sendResult(response, res, 0)
else: # -------------------------------------------------------------- --
raise NotImplementedError('unknown state %r' % auth_state)
# if there is no otp in the request, we assume that we
# have to poll for the transaction state
if not state_data:
raise Exception('invalid state data')
verified = False
transid = state_data.get('transactionid')
va = ValidationHandler()
ok, opt = va.check_status(transid=transid, user=user,
serial=None, password='passw',
)
if ok and opt and opt.get('transactions', {}).get(transid):
verified = opt.get(
'transactions', {}).get(
transid).get(
'valid_tan')
if verified:
(cookie, expires,
expiration) = create_auth_cookie(user, self.client)
response.set_cookie('user_selfservice', cookie,
secure=secure_cookie,
expires=expires)
c.audit['action_detail'] = "expires: %s " % expiration
c.audit['info'] = "%r logged in " % user
Session.commit()
return sendResult(response, verified, 0)
def _login_with_otp(self, user, passw, param): def _login_with_otp(self, user, passw, param):
""" """
handle login with otp - either if provided directly or delayed handle login with otp - either if provided directly or delayed
:param user: User Object of the identified user :param user: User Object of the identified user
:param password: the password parameter :param password: the password parameter
:param param: the request parameters :param param: the request parameters
""" """
skipping to change at line 704 skipping to change at line 737
return sendResult(response, False, 0) return sendResult(response, False, 0)
# ------------------------------------------------------------------ -- # ------------------------------------------------------------------ --
# if there is an otp, we can do a direct otp authentication # if there is an otp, we can do a direct otp authentication
otp = param.get('otp', '') otp = param.get('otp', '')
if otp: if otp:
vh = ValidationHandler() vh = ValidationHandler()
res, reply = vh.checkUserPass(user, otp) res, reply = vh.checkUserPass(user, passw + otp)
if res: if res:
log.debug("Successfully authenticated user %r:", user) log.debug("Successfully authenticated user %r:", user)
(cookie, expires, (cookie, expires,
expiration) = create_auth_cookie(user, self.client) expiration) = create_auth_cookie(user, self.client)
response.set_cookie('user_selfservice', cookie, response.set_cookie('user_selfservice', cookie,
secure=secure_cookie, secure=secure_cookie,
expires=expires) expires=expires)
skipping to change at line 795 skipping to change at line 828
otp: optional the otp otp: optional the otp
return: {result : {value: bool} } return: {result : {value: bool} }
""" """
try: try:
param = self.request_params.copy() param = self.request_params.copy()
# -------------------------------------------------------------- -- # -------------------------------------------------------------- --
# if this is an preauthenticated login we continue # if this is an pre-authenticated login we continue
# with the authetication states # with the authentication states
user_selfservice_cookie = request.cookies.get('user_selfservice') user_selfservice_cookie = request.cookies.get('user_selfservice')
# check if this cookie is still valid # check if this cookie is still valid
auth_info = get_cookie_authinfo(user_selfservice_cookie) auth_info = get_cookie_authinfo(user_selfservice_cookie)
if (auth_info[0] and if (auth_info[0] and
check_session(request, auth_info[0], auth_info[1])): check_session(request, auth_info[0], auth_info[1])):
return self._login_with_cookie(user_selfservice_cookie, param) return self._login_with_cookie(user_selfservice_cookie, param)
# if there is a cookie but could not be found in cache # if there is a cookie but could not be found in cache
# we remove the outdated client cookie # we remove the out dated client cookie
if user_selfservice_cookie and not auth_info[0]: if user_selfservice_cookie and not auth_info[0]:
response.delete_cookie('user_selfservice') response.delete_cookie('user_selfservice')
abort(401, _("No valid session!"))
# -------------------------------------------------------------- -- # -------------------------------------------------------------- --
# identify the user # identify the user
user = self._identify_user(params=param) user = self._identify_user(params=param)
if not user: if not user:
raise UserNotFound('user %r not found!' % param.get('login')) raise UserNotFound('user %r not found!' % param.get('login'))
self.authUser = user self.authUser = user
skipping to change at line 854 skipping to change at line 889
return self._login_with_password_only(user, password) return self._login_with_password_only(user, password)
return self._login_with_otp(user, password, param) return self._login_with_otp(user, password, param)
else: else:
return self._login_with_password_only(user, password) return self._login_with_password_only(user, password)
# -------------------------------------------------------------- -- # -------------------------------------------------------------- --
except (webob.exc.HTTPUnauthorized, webob.exc.HTTPForbidden) as exx:
log.error('userservice login failed: %r', exx)
c.audit['info'] = ("%r" % exx)[:80]
c.audit['success'] = False
return exx
except Exception as exx: except Exception as exx:
log.exception('userservice login failed: %r', exx) log.error('userservice login failed: %r', exx)
c.audit['info'] = ("%r" % exx)[:80] c.audit['info'] = ("%r" % exx)[:80]
c.audit['success'] = False c.audit['success'] = False
Session.rollback() Session.rollback()
return sendResult(response, False, 0) return sendResult(response, False, 0)
finally: finally:
Session.close() Session.close()
 End of changes. 55 change blocks. 
106 lines changed or deleted 149 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)