Add the concept of require_fresh_login to both the backend and frontend. Sensitive methods will now be marked with the annotation, which requires that the user has performed a login within 10 minutes or they are asked to do so in the UI before running the operation again.

This commit is contained in:
Joseph Schorr 2014-09-04 14:24:20 -04:00
parent 1e7e012b92
commit e783df31e0
9 changed files with 174 additions and 61 deletions

View file

@ -9,7 +9,7 @@ from app import app, billing as stripe, authentication
from endpoints.api import (ApiResource, nickname, resource, validate_json_request, request_error,
log_action, internal_only, NotFound, require_user_admin, parse_args,
query_param, InvalidToken, require_scope, format_date, hide_if, show_if,
license_error)
license_error, require_fresh_login)
from endpoints.api.subscribe import subscribe
from endpoints.common import common_login
from data import model
@ -117,10 +117,6 @@ class User(ApiResource):
'type': 'object',
'description': 'Fields which can be updated in a user.',
'properties': {
'current_password': {
'type': 'string',
'description': 'The user\'s current password',
},
'password': {
'type': 'string',
'description': 'The user\'s password',
@ -148,6 +144,7 @@ class User(ApiResource):
return user_view(user)
@require_user_admin
@require_fresh_login
@nickname('changeUserDetails')
@internal_only
@validate_json_request('UpdateUser')
@ -156,22 +153,8 @@ class User(ApiResource):
user = get_authenticated_user()
user_data = request.get_json()
def verify_current_password(user, user_data):
current_password = user_data.get('current_password', '')
verified = False
try:
verified = model.verify_user(user.username, current_password)
except:
pass
if not verified:
raise request_error(message='Current password does not match')
try:
if 'password' in user_data:
verify_current_password(user, user_data)
logger.debug('Changing password for user: %s', user.username)
log_action('account_change_password', user.username)
model.change_password(user, user_data['password'])
@ -181,8 +164,6 @@ class User(ApiResource):
model.change_invoice_email(user, user_data['invoice_email'])
if 'email' in user_data and user_data['email'] != user.email:
verify_current_password(user, user_data)
new_email = user_data['email']
if model.find_user_by_email(new_email):
# Email already used.
@ -377,6 +358,37 @@ class Signin(ApiResource):
return conduct_signin(username, password)
@resource('/v1/signin/verify')
@internal_only
class VerifyUser(ApiResource):
""" Operations for verifying the existing user. """
schemas = {
'VerifyUser': {
'id': 'VerifyUser',
'type': 'object',
'description': 'Information required to verify the signed in user.',
'required': [
'password',
],
'properties': {
'password': {
'type': 'string',
'description': 'The user\'s password',
},
},
},
}
@require_user_admin
@nickname('verifyUser')
@validate_json_request('VerifyUser')
def post(self):
""" Verifies the signed in the user with the specified credentials. """
signin_data = request.get_json()
password = signin_data['password']
return conduct_signin(get_authenticated_user().username, password)
@resource('/v1/signout')
@internal_only
class Signout(ApiResource):