Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • rc/account-app
  • louistw/account-app
  • krish94/self-reg-form
  • dwheel7/self-reg-form
  • dwheel7/feature-reanme-self-reg-app-to-account-app
  • atlurie/account-app
  • dwheel7/account-app
7 results
Show changes
docs/images/rabbitmq-agents-flowchart.png

84 KiB

docs/images/rabbitmq-agents-messages.png

58.5 KiB

docs/images/rc-network .png

106 KiB

docs/images/security_rules.png

311 KiB

docs/images/site_example.png

478 KiB

This diff is collapsed.
welcome_message = "The information below will be used to create your account. Please fill in the reason for requesting your account as this helps us understand our user base.<br>Contact <a href='mailto:support@listserv.uab.edu'>Research Computing</a> if you have any questions." """
cancel_message = "Close current tab to end session.<br>Contact <a href="'mailto:support@listserv.uab.edu'">Research Computing</a> if you have any questions." Messages used in account management app
error_message = "An error occurred while creating your account. Research Computing team has been notified and is working on fixing it.<br>Contact <a href='mailto:support@listserv.uab.edu'>Research Computing</a> if you have any questions." """
unauthorized_message = "Your UAB Research Computing account is currently on hold.<br>Accounts are put on hold if there are changes with your UAB affiliation or if there is an issue on one of the platforms.<br>Please contact <a href="'mailto:support@listserv.uab.edu'">Research Computing</a> or attend the weekly office hours to resolve any issues."
account_hold_message = "Your UAB Research Computing account is currently on hold.<br>Please contact <a href="'mailto:support@listserv.uab.edu'">Research Computing</a> or attend the weekly office hours to resolve any issues." welcome_message = (
pre_certification_message = "Welcome back to the UAB Research Computing services page.<br>Annual account certification is required for continued access to Research Computing services. <br> To continue with the self certification process click on continue below" "The information below will be used to create your account. Please fill in"
certification_message = "Welcome back to the UAB Research Computing services page.<br>The usage of this resource is governed by UAB IT's <a href=' https://secure2.compliancebridge.com/uab/public/index.php?fuseaction=print.preview&docID=786' target='_blank'>Acceptable Use Policy </a> and <a href='https://www.uab.edu/it/home/policies/data-classification/classification-overview' target='_blank'>Data Classification Policy</a><br>To read and understand all UAB IT policies click <a href=' https://www.uab.edu/it/home/policies' target='_blank'>here</a><br>Verify your information in the form below and hit the Certify Account button when you are done." " the reason for requesting your account as this helps us understand our"
good_standing_message= "Your account is in good standing. Click <a href=https://rc.uab.edu>here</a> to proceed to dashboard" " user base. Please be aware that the use of this resource is governed by"
" <a href='https://www.uab.edu/it/home/policies' target='_blank'>UAB"
" Information Technology Security Policies.</a><br><br>Contact <a"
" href='mailto:support@listserv.uab.edu'>Research Computing</a> if you"
" have any questions.<br>"
)
cancel_message = (
"Close current tab to end session.<br>Contact <a href="
"mailto:support@listserv.uab.edu"
">Research Computing</a> if you have any questions.<br>"
)
error_message = (
"An error occurred while creating your account. Research Computing team"
" has been notified and is working on fixing it.<br>Contact <a"
" href='mailto:support@listserv.uab.edu'>Research Computing</a> if you"
" have any questions.<br>"
)
unauthorized_message = (
"Your UAB login is not authorized to use UAB Research Computing Systems."
" Contact <a href='mailto:support@listserv.uab.edu'>Research Computing</a>"
" to resolve this issue.<br>"
)
account_hold_message = (
"Your UAB Research Computing account is currently on hold.<br>Please"
" contact <a href=mailto:support@listserv.uab.edu>Research Computing</a>"
" or attend the weekly <a href='https://uabrc.github.io/#contact-us'"
" target='_blank'>office hours</a> to resolve this issue.<br>"
)
pre_certification_message = (
"Annual account certification is required for continued access to Research"
" Computing Systems.<br>To continue with the self certification process"
" click on continue below.<br><br>"
)
certification_message = (
"This resource is governed by <a"
" href='https://www.uab.edu/it/home/policies' target='_blank'>UAB"
" Information Technology Security Policies.</a><br><br>Please verify your"
" information in the form below and press the Certify Account to complete"
" the certification process.<br>"
)
good_standing_message = (
"Your account is in good standing. Click <a"
" href=https://rc.uab.edu>here</a> to proceed to dashboard.<br>"
)
...@@ -3,6 +3,7 @@ line-length = 79 ...@@ -3,6 +3,7 @@ line-length = 79
target-version = ['py36'] target-version = ['py36']
preview = true preview = true
[tool.pylint.main] [tool.pylint.main]
disable = ["import-error", "unused-argument", "broad-except"] disable = ["invalid-name", "import-error", "unused-argument", "broad-except"]
ignore = ["config.py", "tests.py"]
[tool.pylint.format] [tool.pylint.format]
max-line-length = 79 max-line-length = 79
"""
This python script conatins functions that talk with Flask frontend over
socketio.
It has functions to join a unique room, creating an account and
certifying an account.
"""
# run.py # run.py
# standard imports
import os import os
import time import time
import tasks
import vars
# third-party imports
from flask import session from flask import session
from flask_socketio import SocketIO, join_room from flask_socketio import SocketIO, join_room
from app import create_app
from gevent import monkey from gevent import monkey
# local imports
# pylint: disable=wrong-import-order
import tasks
import app_vars
# pylint: enable=wrong-import-order
from app import create_app
monkey.patch_all(subprocess=True) monkey.patch_all(subprocess=True)
config_name = os.getenv('FLASK_CONFIG') config_name = os.getenv("FLASK_CONFIG")
app = create_app(config_name) app = create_app(config_name)
app.config['SECRET_KEY'] = vars.key app.config["SECRET_KEY"] = app_vars.key
socketio = SocketIO(app, cors_allowed_origins=vars.cors_allowed_origins, message_queue=vars.message_queue) socketio = SocketIO(
app,
cors_allowed_origins=app_vars.cors_allowed_origins,
message_queue=app_vars.message_queue,
)
@socketio.on('join_room') @socketio.on("join_room")
def on_room(json): def on_room(json):
room = str(session['uid']) """
referrer = json['referrer'] This function creates a unique room/flask session id, and joins it
Input:
json: conatins config information for the flask session
Output:
Join the unique room.
"""
room = str(session["uid"])
referrer = json["referrer"]
join_room(room) join_room(room)
print('\t\t\t|-----Room ID: ' + room) print("\t\t\t|-----Room ID: " + room)
print('\t\t\t|-----Referrer: ' + referrer) print("\t\t\t|-----Referrer: " + referrer)
@socketio.on('request account')
def request_account(json, methods=['GET', 'POST']): @socketio.on("request account")
print (time.strftime("%m-%d-%Y_%H:%M:%S") + '\tQueue request received: ' + str(json)) def request_account(json):
room = str(session['uid']) """
print("Room: {}".format(room)) This function is called by the Flask frontend on an account request.
Input:
json: This contains information needed for the user that needs to be
created from the frontend.
methods: Defaults to ["GET", "POST"].
Output:
Send the json to Celery tasks file for account creation.
"""
print(
time.strftime("%m-%d-%Y_%H:%M:%S")
+ "\tQueue request received: "
+ str(json)
)
room = str(session["uid"])
print(f"Room: {room}")
try: try:
tasks.celery_create_account.delay(json, session=room ) tasks.celery_create_account.delay(json, session=room)
except Exception as e: except Exception as e:
print(time.strftime("%m-%d-%Y_%H:%M:%S") + "\tError in account creation: ", e) print(
time.strftime("%m-%d-%Y_%H:%M:%S")
+ "\tError in account creation: ",
e,
)
socketio.emit("Account creation failed", room) socketio.emit("Account creation failed", room)
@socketio.on('request certification')
def certify_account(json, methods=['GET', 'POST']): @socketio.on("request certification")
print (time.strftime("%m-%d-%Y_%H:%M:%S") + '\tQueue request received: ' + str(json)) def certify_account(json):
room = str(session['uid']) """
print("CERTIFY Room: {}".format(room)) This function is called by the Flask frontend from self certification page.
Inputs:
json: Conatins information about the user that needs to be certified
from the frontend.
methods: Defaults to ["GET", "POST"].
Outputs:
Send the json to Celery tasks file for user certification.
"""
print(
time.strftime("%m-%d-%Y_%H:%M:%S")
+ "\tQueue request received: "
+ str(json)
)
room = str(session["uid"])
print(f"CERTIFY Room: {room}")
try: try:
tasks.celery_certify_account(json, session=room ) tasks.celery_certify_account(json, session=room)
except Exception as e: except Exception as e:
print(time.strftime("%m-%d-%Y_%H:%M:%S") + "\tError in account certification: ", e) print(
time.strftime("%m-%d-%Y_%H:%M:%S")
+ "\tError in account certification: ",
e,
)
socketio.emit("Account certification failed", room) socketio.emit("Account certification failed", room)
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0') if __name__ == "__main__":
socketio.run(app, host="0.0.0.0")
import vars """
import sys This python module defines celery tasks for following fucntions:
* Account creation
* Account certification
"""
# standard imports
import json import json
import sys
import time import time
import signal
# third-party imports
from celery import Celery from celery import Celery
from flask_socketio import SocketIO from flask_socketio import SocketIO
sys.path.append(vars.rabbitmq_agents_loc) # local imports
import rc_util import app_vars
sys.path.append(app_vars.rabbitmq_agents_loc)
# pylint: disable=wrong-import-position
import rc_util # noqa: E402
broker_url = vars.broker_url # pylint: enable=wrong-import-position
celery = Celery(vars.celery_app, broker=broker_url)
socketio = SocketIO(message_queue=vars.message_queue)
broker_url = app_vars.broker_url
celery = Celery(app_vars.celery_app, broker=broker_url)
socketio = SocketIO(message_queue=app_vars.message_queue)
timeout = 30 timeout = 30
def gen_f(room): def gen_f(room):
"""
This function defines the callback function for creating account process.
Inputs:
room: Room/session ID for the flask session, so that communications
are going to the right session.
Output:
RabbitMQ callback function.
"""
def callback(channel, method, properties, body): def callback(channel, method, properties, body):
"""
This function defines the RabbitMQ callback function executed after
account creation process.
Inputs:
channel: channel over which the RabbitMQ communication is
happening.
method: Defines meta information regarding the message delivery.
properties: user-defined properties on the message
body: Message that is passed throughout account creation process
across multiple agents.
Output:
Send appropriate message to the frontend, for account creation
success or failure. And delete the queue.
"""
msg = json.loads(body) msg = json.loads(body)
username = msg['username'] username = msg["username"]
queuename = msg['queuename'] queuename = msg["queuename"]
if msg['success']: if msg["success"]:
print(f'Account for {username} has been created.') print(f"Account for {username} has been created.")
send_msg('account ready', room) send_msg("account ready", room)
else: else:
print(f"There's some issue while creating account for {username}") print(f"There's some issue while creating account for {username}")
errmsg = msg.get('errmsg', []) errmsg = msg.get("errmsg", [])
for err in errmsg: for err in errmsg:
print(err) print(err)
socketio.emit('account error', errmsg, room= room) socketio.emit("account error", errmsg, room=room)
rc_util.rc_rmq.stop_consume() rc_util.rc_rmq.stop_consume()
rc_util.rc_rmq.delete_queue(queuename) rc_util.rc_rmq.delete_queue(queuename)
return callback return callback
def certify_gen_f(room): def certify_gen_f(room):
"""
This function defines the callback function for certifying account process.
Inputs:
room: Room/session ID for the flask session, so that communications are
going to the right session.
Output:
RabbitMQ callback function.
"""
def callback(channel, method, properties, body): def callback(channel, method, properties, body):
"""
This function defines the RabbitMQ callback function executed after
account certification process.
Inputs:
channel: channel over which the RabbitMQ communication is happening
method: Defines meta information regarding the message delivery.
properties: user-defined properties on the message
body: Message that is passed throughout account creation process
across multiple agents.
Output:
Send appropriate message to the frontend, for account certification
success or failure. And delete the queue.
"""
msg = json.loads(body) msg = json.loads(body)
username = msg['username'] username = msg["username"]
queuename = msg['queuename'] queuename = msg["queuename"]
if msg['success']: if msg["success"]:
print(f'Account for {username} has been certified.') print(f"Account for {username} has been certified.")
send_msg('certified', room) send_msg("certified", room)
else: else:
print(f"There's some issue while certifying account for {username}") print(
errmsg = msg.get('errmsg', []) f"There's some issue while certifying account for {username}"
)
errmsg = msg.get("errmsg", [])
for err in errmsg: for err in errmsg:
print(err) print(err)
socketio.emit('certify error', errmsg, room= room) socketio.emit("certify error", errmsg, room=room)
rc_util.rc_rmq.stop_consume() rc_util.rc_rmq.stop_consume()
rc_util.rc_rmq.delete_queue(queuename) rc_util.rc_rmq.delete_queue(queuename)
return callback return callback
def send_msg(event, room): def send_msg(event, room):
"""
This function is used to send messages via socketio
Input:
string event, room:
Output:
string: emit event to room
"""
socketio.emit(event, room=room) socketio.emit(event, room=room)
def timeout_handler(signum, frame):
print("Process timeout, there's might some issue with agents") # def timeout_handler(signum, frame):
socketio.emit('account error', errmsg, room= room) # print("Process timeout, there's might some issue with agents")
rc_util.rc_rmq.stop_consume() # socketio.emit("account error", errmsg, room=room)
rc_util.rc_rmq.delete_queue() # rc_util.rc_rmq.stop_consume()
# rc_util.rc_rmq.delete_queue()
@celery.task @celery.task
def celery_create_account(json, session): def celery_create_account(msg, session):
"""
This function is used to create account for new users
Input:
msg: json object of all user attributes and session/room
Output:
gen_f(room): callback to check for success or failure
"""
room = session room = session
username= json['username'] username = msg["username"]
email= json['email'] email = msg["email"]
fullname= json['fullname'] fullname = msg["fullname"]
reason= json['reason'] reason = msg["reason"]
queuename= rc_util.encode_name(username) # aup= msg['aup']
updated_by= f'{username}' queuename = rc_util.encode_name(username)
host= vars.app_host updated_by = f"{username}"
host = app_vars.app_host
print(time.strftime("%m-%d-%Y_%H:%M:%S") + '\tUser ' + username + ' added to queue')
send_msg('creating account', room) print(
time.strftime("%m-%d-%Y_%H:%M:%S")
+ "\tUser "
+ username
+ " added to queue"
)
send_msg("creating account", room)
print(username) print(username)
rc_util.add_account(username, queuename, email, fullname, reason, updated_by, host) rc_util.add_account(
print('sent account info') username, queuename, email, fullname, reason, updated_by, host
print('Waiting for completion...') )
rc_util.consume(queuename, routing_key=f'complete.{queuename}', callback=gen_f(room)) print("sent account info")
print("Waiting for completion...")
rc_util.consume(
queuename, routing_key=f"complete.{queuename}", callback=gen_f(room)
)
@celery.task @celery.task
def celery_certify_account(json, session): def celery_certify_account(msg, session):
"""
This function is used to certify account for existing users
Input:
msg: json object of all user attributes and session/room
Output:
gen_f(room): callback to check for success or failure
"""
room = session room = session
username= json['username'] username = msg["username"]
email= json['email'] queuename = rc_util.encode_name(username)
fullname= json['fullname'] updated_by = f"{username}"
queuename= rc_util.encode_name(username) host = app_vars.app_host
updated_by= f'{username}'
host= vars.app_host print(
"CERTIFY : "
print("CERTIFY : "+time.strftime("%m-%d-%Y_%H:%M:%S") + '\tUser ' + username + ' added to queue') + time.strftime("%m-%d-%Y_%H:%M:%S")
send_msg('certifying account', room) + "\tUser "
+ username
+ " added to queue"
)
send_msg("certifying account", room)
print(username) print(username)
rc_util.certify_account(username, queuename, 'ok', 'all', updated_by, host) rc_util.certify_account(username, queuename, "ok", "all", updated_by, host)
print('sent account info') print("sent account info")
print('Waiting for certification...') print("Waiting for certification...")
rc_util.consume(queuename, routing_key=f'certified.{queuename}', callback=certify_gen_f(room)) rc_util.consume(
queuename,
routing_key=f"certified.{queuename}",
callback=certify_gen_f(room),
)
...@@ -3,23 +3,22 @@ ...@@ -3,23 +3,22 @@
import unittest import unittest
import flask import flask
from flask import abort, url_for, g from flask import abort, url_for
from flask_testing import TestCase from flask_testing import TestCase
from app import create_app from app import create_app
class TestBase(TestCase): class TestBase(TestCase):
def create_app(self): def create_app(self):
app = create_app('testing') app = create_app("testing")
return app return app
def setUp(self): def setUp(self):
""" """
Will be called before every test Will be called before every test
""" """
app = create_app('testing') app = create_app("testing")
return app return app
def tearDown(self): def tearDown(self):
...@@ -41,7 +40,7 @@ class TestViews(TestBase): ...@@ -41,7 +40,7 @@ class TestViews(TestBase):
Test that homepage is accessible. Test that homepage is accessible.
""" """
response = self.client.get(url_for('index')) response = self.client.get(url_for("index"))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
# with self.app.test_client() as c: # with self.app.test_client() as c:
...@@ -52,10 +51,10 @@ class TestViews(TestBase): ...@@ -52,10 +51,10 @@ class TestViews(TestBase):
""" """
Test that all resources load are found. Test that all resources load are found.
""" """
with self.app.test_request_context('/?redir=test'): with self.app.test_request_context("/?redir=test"):
assert flask.request.path == '/' assert flask.request.path == "/"
c = flask.app.request.args['redir'] c = flask.app.request.args["redir"]
assert c == 'test' assert c == "test"
# def test_logout_view(self): # def test_logout_view(self):
# """ # """
...@@ -70,32 +69,31 @@ class TestViews(TestBase): ...@@ -70,32 +69,31 @@ class TestViews(TestBase):
class TestErrorPages(TestBase): class TestErrorPages(TestBase):
def test_403_forbidden(self): def test_403_forbidden(self):
# create route to abort the request with the 403 Error # create route to abort the request with the 403 Error
@self.app.route('/403') @self.app.route("/403")
def forbidden_error(): def forbidden_error():
abort(403) abort(403)
response = self.client.get('/403') response = self.client.get("/403")
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertTrue("403 Error" in response.data) self.assertTrue("403 Error" in response.data)
def test_404_not_found(self): def test_404_not_found(self):
response = self.client.get('/nothinghere') response = self.client.get("/nothinghere")
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
self.assertTrue("404 Error" in response.data) self.assertTrue("404 Error" in response.data)
def test_500_internal_server_error(self): def test_500_internal_server_error(self):
# create route to abort the request with the 500 Error # create route to abort the request with the 500 Error
@self.app.route('/500') @self.app.route("/500")
def internal_server_error(): def internal_server_error():
abort(500) abort(500)
response = self.client.get('/500') response = self.client.get("/500")
self.assertEqual(response.status_code, 500) self.assertEqual(response.status_code, 500)
self.assertTrue("500 Error" in response.data) self.assertTrue("500 Error" in response.data)
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()