diff --git a/powerdnsadmin/routes/admin.py b/powerdnsadmin/routes/admin.py index f4ff840..8af3daa 100644 --- a/powerdnsadmin/routes/admin.py +++ b/powerdnsadmin/routes/admin.py @@ -183,7 +183,7 @@ def manage_user(): # Then delete the user result = user.delete() if result: - history = History(msg='Delete username {0}'.format(data), + history = History(msg='Delete user {0}'.format(data), created_by=current_user.username) history.add() return make_response( diff --git a/powerdnsadmin/routes/index.py b/powerdnsadmin/routes/index.py index 81008ee..2696866 100644 --- a/powerdnsadmin/routes/index.py +++ b/powerdnsadmin/routes/index.py @@ -158,6 +158,7 @@ def login(): session['user_id'] = user.id login_user(user, remember=False) session['authentication_type'] = 'OAuth' + signin_history(user.username, 'Google OAuth', True) return redirect(url_for('index.index')) if 'github_token' in session: @@ -184,6 +185,7 @@ def login(): session['user_id'] = user.id session['authentication_type'] = 'OAuth' login_user(user, remember=False) + signin_history(user.username, 'Github OAuth', True) return redirect(url_for('index.index')) if 'azure_token' in session: @@ -222,6 +224,7 @@ def login(): session['user_id'] = user.id session['authentication_type'] = 'OAuth' login_user(user, remember=False) + signin_history(user.username, 'Azure OAuth', True) return redirect(url_for('index.index')) if 'oidc_token' in session: @@ -247,6 +250,7 @@ def login(): session['user_id'] = user.id session['authentication_type'] = 'OAuth' login_user(user, remember=False) + signin_history(user.username, 'OIDC OAuth', True) return redirect(url_for('index.index')) if request.method == 'GET': @@ -269,6 +273,7 @@ def login(): auth = user.is_validate(method=auth_method, src_ip=request.remote_addr) if auth == False: + signin_history(user.username, 'LOCAL', False) return render_template('login.html', saml_enabled=SAML_ENABLED, error='Invalid credentials') @@ -285,6 +290,7 @@ def login(): if otp_token and otp_token.isdigit(): good_token = user.verify_totp(otp_token) if not good_token: + signin_history(user.username, 'LOCAL', False) return render_template('login.html', saml_enabled=SAML_ENABLED, error='Invalid credentials') @@ -294,6 +300,7 @@ def login(): error='Token required') login_user(user, remember=remember_me) + signin_history(user.username, 'LOCAL', True) return redirect(session.get('next', url_for('index.index'))) @@ -306,6 +313,38 @@ def clear_session(): logout_user() +def signin_history(username, authenticator, success): + # Get user ip address + if request.headers.getlist("X-Forwarded-For"): + request_ip = request.headers.getlist("X-Forwarded-For")[0] + request_ip = request_ip.split(',')[0] + else: + request_ip = request.remote_addr + + # Write log + str_success = 'succeeded' if success else 'failed' + if success: + str_success = 'succeeded' + current_app.logger.info( + "User {} authenticated successfully via {} from {}".format( + username, authenticator, request_ip)) + else: + str_success = 'failed' + current_app.logger.warning( + "User {} failed to authenticate via {} from {}".format( + username, authenticator, request_ip)) + + # Write history + History(msg='User {} authentication {}'.format(username, str_success), + detail=str({ + "username": username, + "authenticator": authenticator, + "ip_address": request_ip, + "success": 1 if success else 0 + }), + created_by='System').add() + + @index_bp.route('/logout') def logout(): if current_app.config.get( @@ -465,7 +504,7 @@ def dyndns_update(): # Record content did not change, return 'nochg' history = History( msg= - "DynDNS update: attempted update of {0} but record did not change" + "DynDNS update: attempted update of {0} but record already up-to-date" .format(hostname), created_by=current_user.username) history.add() @@ -474,10 +513,14 @@ def dyndns_update(): result = r.update(domain.name, str(ip)) if result['status'] == 'ok': history = History( - msg= - 'DynDNS update: updated {0} record {1} in zone {2}, it changed from {3} to {4}' - .format(rtype, hostname, domain.name, oldip, str(ip)), - detail=str(result), + msg='DynDNS update: updated {} successfully'.format(hostname), + detail=str({ + "domain": domain.name, + "record": hostname, + "type": rtype, + "old_value": oldip, + "new_value": str(ip) + }), created_by=current_user.username) history.add() response = 'good' @@ -510,9 +553,13 @@ def dyndns_update(): if result['status'] == 'ok': history = History( msg= - 'DynDNS update: created record {0} in zone {1}, it now represents {2}' + 'DynDNS update: created record {0} in zone {1} successfully' .format(hostname, domain.name, str(ip)), - detail=str(result), + detail=str({ + "domain": domain.name, + "record": hostname, + "value": str(ip) + }), created_by=current_user.username) history.add() response = 'good' @@ -671,6 +718,7 @@ def saml_authorized(): user.update_profile() session['authentication_type'] = 'SAML' login_user(user, remember=False) + signin_history(user.username, 'SAML', True) return redirect(url_for('index')) else: return render_template('errors/SAML.html', errors=errors)