From 313e820d27413422aca31fc075426adef9c69f0e Mon Sep 17 00:00:00 2001 From: proffapt Date: Wed, 10 Jul 2024 23:25:59 +0530 Subject: [PATCH] docs(readme): update webapp workflow --- README.md | 155 +++++++++++++++++++++------------------------ examples/server.py | 7 +- 2 files changed, 77 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index edfb497..e156fc4 100644 --- a/README.md +++ b/README.md @@ -340,7 +340,7 @@ while True: ## Using in WebApps -To implement the login workflow for `web applications` and `backend systems`, utilize the [session_manager](./src/iitkgp_erp_login/session_manager.py) module. +To implement the login workflow for `web applications` and `backend systems`, utilize the modularised implementation of this package.
@@ -350,23 +350,18 @@ Following is a proof of concept example to achieve the login workflow: ```python import logging -from flask_cors import CORS +import requests +import iitkgp_erp_login.erp as erp from flask import Flask, request, jsonify -from iitkgp_erp_login import session_manager - +import iitkgp_erp_login.utils as erp_utils app = Flask(__name__) -CORS(app) -jwt_secret_key = "top-secret-unhackable-key" headers = { 'timeout': '20', 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/51.0.2704.79 Chrome/51.0.2704.79 Safari/537.36', } -session_manager = session_manager.SessionManager( - jwt_secret_key=jwt_secret_key, headers=headers) - class ErpResponse: def __init__(self, success: bool, message: str = None, data: dict = None, status_code: int = 200): @@ -380,9 +375,10 @@ class ErpResponse: def to_dict(self): response = { - "status": "success" if self.success else "error", - "message": self.message + "status": "success" if self.success else "error" } + if self.message: + response.update({"message": self.message}) if self.data: response.update(self.data) return response @@ -391,19 +387,6 @@ class ErpResponse: return jsonify(self.to_dict()), self.status_code -def handle_auth() -> ErpResponse: - if "Authorization" in request.headers: - header = request.headers["Authorization"].split(" ") - if len(header) == 2: - return ErpResponse(True, data={ - "jwt": header[1] - }).to_response() - else: - return ErpResponse(False, "Poorly formatted authorization header. Should be of format 'Bearer '", status_code=401).to_response() - else: - return ErpResponse(False, "Authentication token not provided", status_code=401).to_response() - - @app.route("/secret-question", methods=["POST"]) def get_secret_question(): try: @@ -412,11 +395,14 @@ def get_secret_question(): if not roll_number: return ErpResponse(False, "Roll Number not provided", status_code=400).to_response() - secret_question, jwt = session_manager.get_secret_question( - roll_number) + session = requests.Session() + secret_question = erp.get_secret_question( + headers=headers, session=session, roll_number=roll_number, log=True) + sessionToken = erp_utils.get_cookie(session, 'JSESSIONID') + return ErpResponse(True, data={ - "secret_question": secret_question, - "jwt": jwt + "SECRET_QUESTION": secret_question, + "SESSION_TOKEN": sessionToken }).to_response() except Exception as e: return ErpResponse(False, str(e), status_code=500).to_response() @@ -425,19 +411,29 @@ def get_secret_question(): @app.route("/request-otp", methods=["POST"]) def request_otp(): try: - jwt = None - auth_resp, status_code = handle_auth() - if status_code != 200: - return auth_resp, status_code - else: - jwt = auth_resp.get_json().get("jwt") - - password = request.form.get("password") - secret_answer = request.form.get("secret_answer") - if not all([password, secret_answer]): - return ErpResponse(False, "Missing password or secret answer", status_code=400).to_response() - - session_manager.request_otp(jwt, password, secret_answer) + sessionToken = request.headers["Session-Token"] + if not sessionToken: + return ErpResponse(False, "Session-Token header not found", status_code=400).to_response() + + data = request.form + roll_number = data.get("roll_number") + password = data.get("password") + secret_answer = data.get("secret_answer") + if not all([roll_number, password, secret_answer]): + return ErpResponse(False, "Missing roll_number or password or secret answer", status_code=400).to_response() + + login_details = erp.get_login_details( + ROLL_NUMBER=roll_number, + PASSWORD=password, + secret_answer=secret_answer, + sessionToken=sessionToken + ) + + session = requests.Session() + erp_utils.set_cookie(session, 'JSESSIONID', sessionToken) + erp.request_otp(headers=headers, session=session, + login_details=login_details, log=True) + return ErpResponse(True, message="OTP has been sent to your connected email accounts").to_response() except Exception as e: return ErpResponse(False, str(e), status_code=500).to_response() @@ -446,38 +442,34 @@ def request_otp(): @app.route("/login", methods=["POST"]) def login(): try: - jwt = None - auth_resp, status_code = handle_auth() - if status_code != 200: - return auth_resp, status_code - else: - jwt = auth_resp.get_json().get("jwt") - - password = request.form.get("password") - secret_answer = request.form.get("secret_answer") - otp = request.form.get("otp") - if not all([secret_answer, password, otp]): - return ErpResponse(False, "Missing password, secret answer or otp", status_code=400).to_response() - - session_manager.login(jwt, password, secret_answer, otp) - return ErpResponse(True, message="Logged in to ERP").to_response() - except Exception as e: - return ErpResponse(False, str(e), status_code=500).to_response() - + sessionToken = request.headers["Session-Token"] + if not sessionToken: + return ErpResponse(False, "Session-Token header not found", status_code=400).to_response() -@app.route("/logout", methods=["GET"]) -def logout(): - try: - jwt = None - auth_resp, status_code = handle_auth() - if status_code != 200: - return auth_resp, status_code - else: - jwt = auth_resp.get_json().get("jwt") - - session_manager.end_session(jwt=jwt) + data = request.form + roll_number = data.get("roll_number") + password = data.get("password") + secret_answer = data.get("secret_answer") + otp = data.get("otp") + if not all([roll_number, password, secret_answer, otp]): + return ErpResponse(False, "Missing roll_number or password or secret answer or otp", status_code=400).to_response() + + login_details = erp.get_login_details( + ROLL_NUMBER=roll_number, + PASSWORD=password, + secret_answer=secret_answer, + sessionToken=sessionToken + ) + login_details["email_otp"] = otp + + session = requests.Session() + erp_utils.set_cookie(session, 'JSESSIONID', sessionToken) + ssoToken = erp.signin(headers=headers, session=session, + login_details=login_details, log=True) - return ErpResponse(True, message="Logged out of ERP").to_response() + return ErpResponse(True, data={ + "ssoToken": ssoToken + }).to_response() except Exception as e: return ErpResponse(False, str(e), status_code=500).to_response() @@ -485,14 +477,9 @@ def logout(): @app.route("/timetable", methods=["POST"]) def timetable(): try: - jwt = None - auth_resp, status_code = handle_auth() - if status_code != 200: - return auth_resp, status_code - else: - jwt = auth_resp.get_json().get("jwt") - - _, ssoToken = session_manager.get_erp_session(jwt=jwt) + ssoToken = request.headers["SSO-Token"] + if not ssoToken: + return ErpResponse(False, "SSO-Token header not found", status_code=400).to_response() ERP_TIMETABLE_URL = "https://erp.iitkgp.ac.in/Acad/student/view_stud_time_table.jsp" data = { @@ -500,10 +487,14 @@ def timetable(): "module_id": '16', "menu_id": '40', } - r = session_manager.request( - jwt=jwt, method='POST', url=ERP_TIMETABLE_URL, headers=headers, data=data) + + session = requests.Session() + erp_utils.populate_session_with_login_tokens(session, ssoToken) + r = session.post(headers=headers, url=ERP_TIMETABLE_URL, data=data) + return ErpResponse(True, data={ - "status_code": r.status_code + "status_code": r.status_code, + "content": r.text }).to_response() except Exception as e: return ErpResponse(False, str(e), status_code=500).to_response() diff --git a/examples/server.py b/examples/server.py index 48d8679..823e3d4 100644 --- a/examples/server.py +++ b/examples/server.py @@ -1,8 +1,8 @@ import logging import requests import iitkgp_erp_login.erp as erp -import iitkgp_erp_login.utils as erp_utils from flask import Flask, request, jsonify +import iitkgp_erp_login.utils as erp_utils app = Flask(__name__) @@ -71,14 +71,15 @@ def request_otp(): if not all([roll_number, password, secret_answer]): return ErpResponse(False, "Missing roll_number or password or secret answer", status_code=400).to_response() - session = requests.Session() - erp_utils.set_cookie(session, 'JSESSIONID', sessionToken) login_details = erp.get_login_details( ROLL_NUMBER=roll_number, PASSWORD=password, secret_answer=secret_answer, sessionToken=sessionToken ) + + session = requests.Session() + erp_utils.set_cookie(session, 'JSESSIONID', sessionToken) erp.request_otp(headers=headers, session=session, login_details=login_details, log=True)