From 4a6257ec6c1eeb7df9758b79065fcb34a2113529 Mon Sep 17 00:00:00 2001 From: brandon Date: Thu, 22 Feb 2024 13:40:14 -0800 Subject: [PATCH] initial commit --- .gitignore | 1 + __pycache__/ad.cpython-312.pyc | Bin 0 -> 641 bytes __pycache__/db.cpython-312.pyc | Bin 0 -> 2745 bytes __pycache__/mfa.cpython-312.pyc | Bin 0 -> 632 bytes __pycache__/yamlcon.cpython-312.pyc | Bin 0 -> 755 bytes accounts.py | 174 ++++++++++++++++++++++++++++ ad.py | 8 ++ db.py | 66 +++++++++++ mfa.db | Bin 0 -> 12288 bytes mfa.py | 14 +++ templates/2fa.html | 18 +++ templates/home.html | 19 +++ yamlcon.py | 10 ++ 13 files changed, 310 insertions(+) create mode 100644 .gitignore create mode 100644 __pycache__/ad.cpython-312.pyc create mode 100644 __pycache__/db.cpython-312.pyc create mode 100644 __pycache__/mfa.cpython-312.pyc create mode 100644 __pycache__/yamlcon.cpython-312.pyc create mode 100644 accounts.py create mode 100644 ad.py create mode 100644 db.py create mode 100644 mfa.db create mode 100644 mfa.py create mode 100644 templates/2fa.html create mode 100644 templates/home.html create mode 100644 yamlcon.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..79cfe50 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +adinfo.yaml diff --git a/__pycache__/ad.cpython-312.pyc b/__pycache__/ad.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec1aa82a9c9ec830f2eca09eafd4a94e669d945a GIT binary patch literal 641 zcmZ8e&ubGw6rS1L)GF-8U(G>1H&U{p$Od5a1K~#$RHDe%WLO zXG+QjkVC`}!+R*jTNoqed_Y@H?uOoPD++NjzuN7}lq7=A+H9c)$Awce2#3hP75~8S zc*=*)z}dB$b6^g0$5XGNJ8*Zc*EtLj^9Fc4?H+nL3Tqn&SEy9|R$N$wXuM?H@r6%o_rS@$=aWUN{FE~})gs!sYMFSFIc&xeBi4-x>ai+N{ zZpnSF-l+si#2A(IGGNV;%Jr z5lo7xD`}Q;VRW>ao3~OlHRF$`lu5#iL+xa_{Nn+3Vxr&1mgsuy7KzkAn8+X=ZI?DLoe5Go(S+5E#)vTTn(Qdc3he_Gq`e_V|5 N4|J#WYPeI${{kB?sPg~- literal 0 HcmV?d00001 diff --git a/__pycache__/db.cpython-312.pyc b/__pycache__/db.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e657884c0972f49860aa08d60e52dae26d0f303 GIT binary patch literal 2745 zcmc&$&rcgi6rS;VcWr}B91L{|lnsrlxFWHtHit%S(IzaaRWQgl4dhVC?5HG zO+b#+Lk}QTBB)Y`dg>K%=zma^bB|Fa>h{p8r``-ivgA|WTmN=|3aM4b+P5?F-kaIo z?|a|)XTRS^p#5;;7xPbvkiT%yY_3M<L5v<#g zz>4cMBL9tvalM(3BUqaVaGm@FW|!C$Zcbb6jB3mobid)hMIO6Ku2r$&=(z1S`j3T@ zuqt;r8ePLxA|;w}?Kjq^1lIAs9M@cj;`_m`9luWAB<~PTAG#=6CKP__e-Z9$i?sKer0X0<#{lbe>1&3#Ov#x>YRLQDf!i z+Il&_O}n@@mq{m`7hsoQQCyfWg87R4?!B}S>E+8x;$`F3nm zI`jm#16zR#5yJfyi3|)rnc4j8g)Df-DjwqXZ})BWedDkCA+3tJM`&s%eX#P=TWUx+ z2#M;LthcBF^DP?v0fP(Ch?eNNG(wu4L8A<9lj3|5AsJbqBpAXKcs||LOQ|IBUW8`u zIKywf5$mE&Qk&K8rW%Y=W)kyrb*gm*-TPQeXwJOyp)%ESF|3A&$nZNdd|ihs4C|uo z$(XhdbTA`s){m}0(_faD$%{F=MJYCb3H=XDyUmOtn8FNhf$3$2PYj>WjLmz!gYgV!nA zYodBXe&qs0OXPnOpgJ>_TF7FhFD^{0sXFSs%aPPteCcEZ=A1PK7m%(Ot(Td3>r2Fsp+>z07f*uet=NCn@^;0Z zrR3aE^7qt1;b2fyM`azhX|KRxk`>of2xx2H%^iZ9`$v2wz}ZCo6xY* zQtF*qO^MAY@%faZEya?lWb@eX3dcgjV_HdRODSa`5t~yJ%gQI(^5jcl^>f?_?DDn$ zAb>odBHs~LTdz5)d=v2gY$0oB)4A-1IlaP0z!Qawt6+LDmqq{SDlLZlUl7sjuZj?Y zmFdUI^w;VLPpDKlprY!NBU1g*@LvMM1A(DBI7D-H-XkY4CJqy8o)7YtQOubiu{U52 lvEf(2R0K-tZzOOm$#nQQ)JMa|qaN(R@Z_?G`q>yn{R1d6;otxO literal 0 HcmV?d00001 diff --git a/__pycache__/mfa.cpython-312.pyc b/__pycache__/mfa.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1ed053dfe33df0590d2606de4ca046863354d73 GIT binary patch literal 632 zcmah`F>BjE6n-aN+O&!jC+*OsL4`t5h6bt{oyY+#dp5FJpPw&3_TqrySjJKt4tVjTUnU6f2 zMKOPd#TXJu$ORlj;tb%JBrayBO9J}a(5f*`FT=&kJo6T&G3X_Bo@*|t06my4@JrGo z=PUm}i*mYnUpo3>j`o~{k%;=-5mxCkh z^pEC9h1jG#j7!$P9W4ImU+zu=Bt?4QNMm7EuxCl%pG1o7mL?$Au`AaMw4QI=u$IUz zY?{T@CMLV|cW?Wvw|(RJU#M>f1J|nB^I5($+`pRls|Tq_Iv4DXe1d?vP-SFqT|&rD QSi7T?6z5L~d0}V%0Iu46^8f$< literal 0 HcmV?d00001 diff --git a/__pycache__/yamlcon.cpython-312.pyc b/__pycache__/yamlcon.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..724f3db5d5f2b16321898f6aa5c02015fb3a6e84 GIT binary patch literal 755 zcmZ8fL2DC16n-;1+hny-(-fPVi)pce;?jelB9W!hlh%rQNH4PPZrha2ZkXK|wmO~|(38}`jN-+bSD!_It4rA`3Gd*`c7 z2*7u-h=UG6Zwx^jEU<_Ji(t`but-9ZmwpPtyotV}NFtK(>;1sghTv$gf$r^L#Y@m6 z3Iswoh*cJ&jN9l{}BCv|utm7q>?Fbh7ZQ{f>v!Xck$^AX`|*&CdDT;;Z5mEC2v zq~E@!E|ncyU87gkyc{vFYP%5&jfxW~zOiIKbUed~6d@c~Be}}UZjfgYs~W*d#DqIy zmJt{cv3>EERE++0?SXG|Uwgz2*YaGg=$W;O?FPQK5C$urt1fVFnHv>fyW`rbZkk@r z4K&f$^xTWpFk+%HKaKUo9r%wiJ%xQGwQjwddvUG{BXaglu}ftoyPuh87hV_MO@7W? zSTBCdOdKR|^OsN@{z<}_@r~B=)^DJw98K?z&urb_y18?H=kCtj?%3roqgVFOkwWpH z=HG4-h5Z91Ci?yiwth+UX=&rEMn7isDY-+_x+-@v49Siv3ua0Zcv{wH6M4$TRS(Yo o0eT35pTg8nUaNRk&9MtyyjJma{1m3HLWelcome, {{ current_user.data.givenName }} + + #

Email: {{ current_user.data.mail }}

+ #

{{ current_user.dn }}

+ # """ + print(current_user) + print(current_user.data) + print(current_user.data['objectSid']) + + # return render_template_string(template) + return render_template('home.html', current_user=current_user, mfaurl=url_for('two_factor')) + +@app.route('/2fa') +def two_factor(): + if not current_user or current_user.is_anonymous: + return redirect(url_for('login')) + + if getMfaSecret(user=current_user.data['sAMAccountName']): + currSecret = "MFA already setup" + code = generateOTP(getMfaSecret(user=current_user.data['sAMAccountName'])) + + elif not getMfaSecret(user=current_user.data['sAMAccountName']): + setupMfaSecret(user=current_user.data['sAMAccountName'], secret=generateSecret()) + # currSecret = current_user.data['mfaSecret'] + currSecret = getMfaSecret(user=current_user.data['sAMAccountName']) + code = '' + + print(currSecret) + return render_template('2fa.html', currSecret=currSecret, code=code, homeurl=url_for('home'), delurl=url_for('delTwoFactor')) + +@app.route('/del2fa') +def delTwoFactor(): + if not current_user or current_user.is_anonymous: + return redirect(url_for('login')) + + removeMfa(user=current_user.data['sAMAccountName']) + + return redirect(url_for('home')) + +@app.route('/manual_login') +def manual_login(): + # Instead of using the form, you can alternatively authenticate + # using the authenticate method. + # This WILL NOT fire the save_user() callback defined above. + # You are responsible for saving your users. + app.ldap3_login_manager.authenticate('username', 'password') + + +@app.route('/login', methods=['GET', 'POST']) +def login(): + template = """ + {{ get_flashed_messages() }} + {{ form.errors }} +
+ + + {{ form.submit() }} + {{ form.hidden_tag() }} +
+ """ + + # Instantiate a LDAPLoginForm which has a validator to check if the user + # exists in LDAP. + form = LDAPLoginForm() + + if form.validate_on_submit(): + # Successfully logged in, We can now access the saved user object + # via form.user. + login_user(form.user) # Tell flask-login to log them in. + return redirect('/') # Send them home + + return render_template_string(template, form=form) + + +if __name__ == '__main__': + app.run() \ No newline at end of file diff --git a/ad.py b/ad.py new file mode 100644 index 0000000..991610d --- /dev/null +++ b/ad.py @@ -0,0 +1,8 @@ +from ms_active_directory import ADDomain + +def updateMfaSecret(user, secret): + domain = ADDomain('corp.bbrunson.com') + session = domain.create_session_as_user('administrator@bbrunson.com', 'Mariposa2502$$$$') + + success = session.overwrite_attribute_for_user(user, 'mfaSecret', + secret) \ No newline at end of file diff --git a/db.py b/db.py new file mode 100644 index 0000000..8b2d221 --- /dev/null +++ b/db.py @@ -0,0 +1,66 @@ +import sqlite3 + +# Function to add a new user to the database +def setupMfaSecret(user, secret): + with sqlite3.connect('mfa.db') as conn: + cursor = conn.cursor() + cursor.execute(''' + INSERT INTO users (user, secret) + VALUES (?, ?) + ''', (user, secret)) + conn.commit() + +# Function to retrieve the number corresponding to a username +def getMfaSecret(user): + with sqlite3.connect('mfa.db') as conn: + cursor = conn.cursor() + cursor.execute(''' + SELECT secret FROM users + WHERE user = ? + ''', (user,)) + result = cursor.fetchone() + if result: + return result[0] + else: + return None + +# Function to update the number for a specific username +def updateMfaSecret(user, secret): + with sqlite3.connect('mfa.db') as conn: + cursor = conn.cursor() + cursor.execute(''' + UPDATE users + SET secret = ? + WHERE user = ? + ''', (secret, user)) + conn.commit() + +def removeMfa(user): + with sqlite3.connect('mfa.db') as conn: + cursor = conn.cursor() + cursor.execute(''' + DELETE FROM users + WHERE user = ? + ''', (user,)) + conn.commit() + +def initializeDb(): + with sqlite3.connect('mfa.db') as conn: + cursor = conn.cursor() + cursor.execute(''' + CREATE TABLE IF NOT EXISTS users ( + user TEXT PRIMARY KEY, + secret TEXT + ) + ''') + +# initializeDb() + +# Example usage +# add_user('user1', 123) +# add_user('user2', 456) + +# print(f"Number for 'user1': {get_number('user1')}") + +# update_number('user1', 789) +# print(f"Updated number for 'user1': {get_number('user1')}") diff --git a/mfa.db b/mfa.db new file mode 100644 index 0000000000000000000000000000000000000000..cdcafc097a8b703efa78bb0c9d9c2a39ce669dec GIT binary patch literal 12288 zcmeI$Jxjwt7zgmXM0^Rfam&!gwXP!mj2ad2_;!@2oY z1V=B29n_(7<^OO`F3-JiGu^N(i@sdf>3EjS ztE{ZlLvsapBF-Y`qR*KcVmk)=70oz{_$Xq5=nWhZvnw9&{aIFJw`EqVg+J!HU2WYu zvnZM7lkBN_n8}-clFsWw)rmSaIZ$15uitDuTQaHnPGmzs00Izz00bZa0SG_<0uX=z z1R$_N0=rc248~=ePm0_Vwl@s=$3f3`ZTD0h#$n*yME2!K@DqL%8uGiS`9WkuKmY;| dfB*y_009U<00Izz00bcLp9BoOv-SOd;0tv-N<#nu literal 0 HcmV?d00001 diff --git a/mfa.py b/mfa.py new file mode 100644 index 0000000..9d03d95 --- /dev/null +++ b/mfa.py @@ -0,0 +1,14 @@ +import pyotp + +def generateOTP(secret): + totp = pyotp.TOTP(secret) + code = totp.now() + print(code) + return code + +# def checkOTP(secret, code): +# totp = pyotp.TOTP(secret) +# return totp.verify(code) + +def generateSecret(): + return pyotp.random_base32() \ No newline at end of file diff --git a/templates/2fa.html b/templates/2fa.html new file mode 100644 index 0000000..d4454da --- /dev/null +++ b/templates/2fa.html @@ -0,0 +1,18 @@ + + + + + + Accounts + + +

{{ currSecret }}

+

{{ code }}

+ + + + + + + + \ No newline at end of file diff --git a/templates/home.html b/templates/home.html new file mode 100644 index 0000000..000b2b0 --- /dev/null +++ b/templates/home.html @@ -0,0 +1,19 @@ + + + + + + Accounts + + +

Welcome, {{ current_user.data.givenName }}

+

Email: {{ current_user.data.mail }}

+

{{ current_user.dn }}

+ + + + + + + + \ No newline at end of file diff --git a/yamlcon.py b/yamlcon.py new file mode 100644 index 0000000..d8ac5b9 --- /dev/null +++ b/yamlcon.py @@ -0,0 +1,10 @@ +import yaml + +def load(path): + with open(path, 'r') as file: + try: + data = yaml.safe_load(file) + return data + except yaml.YAMLError as e: + print(f"Error reading YAML file {path}: {e}") + return None \ No newline at end of file