Skip to content

Commit ecf9c11

Browse files
committed
Merge branch 'loganbertram/BB2-3321-oauth-revoke-endpoint' of github.com:CMSgov/bluebutton-web-server into loganbertram/BB2-3321-oauth-revoke-endpoint
2 parents fc105d9 + 97ca627 commit ecf9c11

File tree

33 files changed

+305
-3319
lines changed

33 files changed

+305
-3319
lines changed

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
FROM --platform=linux/amd64 python:3.8
1+
FROM --platform=linux/amd64 python:3.11
22
ENV PYTHONUNBUFFERED 1
3+
ENV PYDEVD_DISABLE_FILE_VALIDATION 1
34
RUN useradd -m -s /bin/bash DEV
45
USER DEV
56
ADD . /code

Dockerfile.selenium

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM seleniarm/standalone-chromium
22

33
ENV PYTHONUNBUFFERED 1
44
USER root
5-
RUN apt-get update ; apt-get install -yq git curl libpq-dev libffi-dev
5+
#RUN apt-get update ; apt-get install -yq git curl libpq-dev libffi-dev
66
RUN apt-get update ; apt-get install -yq python3 python3-venv
77
RUN ln -s /usr/bin/python3 /usr/local/bin/python
88
RUN useradd -m -s /bin/bash DEV
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM --platform=linux/amd64 python:3.11
2+
# For build CBC Jenkins job ECR image
3+
ENV PYTHONUNBUFFERED 1
4+
5+
RUN mkdir /code
6+
ADD . /code/
7+
WORKDIR /code
8+
9+
RUN pip install --upgrade pip
10+
RUN apt-get update && apt-get install -yq git unzip curl
11+
# Install Chrome for Selenium
12+
RUN curl https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o /chrome.deb \
13+
&& dpkg -i /chrome.deb || apt-get install -yf \
14+
&& rm /chrome.deb
15+
# Install chromedriver for Selenium
16+
RUN wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip \
17+
&& unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/ \
18+
&& chmod +x /usr/local/bin/chromedriver

Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
pipeline {
22
agent {
33
kubernetes {
4-
defaultContainer "bb2-cbc-build-selenium-python38"
5-
yamlFile "Jenkinsfiles/cbc-pod-deployment-config-w-selenium-p38.yaml"
4+
defaultContainer "bb2-cbc-build-selenium-python311"
5+
yamlFile "Jenkinsfiles/cbc-pod-deployment-config-w-selenium-p311.yaml"
66
}
77
}
88

99
environment {
10-
USE_MSLSX = false
10+
USE_MSLSX = true
1111
DJANGO_LOG_JSON_FORMAT_PRETTY = true
1212
DJANGO_SETTINGS_MODULE = "hhs_oauth_server.settings.logging_it"
1313
OAUTHLIB_INSECURE_TRANSPORT = true
@@ -55,6 +55,7 @@ pipeline {
5555
sh """
5656
python -m venv venv
5757
. venv/bin/activate
58+
python -m pip install --upgrade pip setuptools wheel cryptography
5859
make reqs-download
5960
make reqs-install-dev
6061
"""
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: v1
2+
kind: Pod
3+
spec:
4+
containers:
5+
- name: bb2-cbc-build-selenium-python311
6+
image: "public.ecr.aws/f5g8o1y9/bb2-cbc-build-selenium-python311:latest"
7+
tty: true
8+
command: ["tail", "-f"]
9+
imagePullPolicy: Always
10+
nodeSelector:
11+
Agents: true

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ reqs-compile:
44

55
# Note: requirements.dev.txt includes packages from requirements.txt also.
66
reqs-download:
7-
pip download -r requirements/requirements.dev.txt --dest vendor --platform manylinux2014_x86_64 --abi cp38 --no-deps
7+
pip download -r requirements/requirements.dev.txt --dest vendor --platform manylinux2014_x86_64 --abi cp311 --no-deps
88

99
#Note: Only installs prod requirements NOT RECOMMENDED FOR DEVELOPMENT.
1010
reqs-download-prod:
11-
pip download -r requirements/requirements.txt --dest vendor --platform manylinux2014_x86_64 --abi cp38 --no-deps
11+
pip download -r requirements/requirements.txt --dest vendor --platform manylinux2014_x86_64 --abi cp311 --no-deps
1212

1313
reqs-install:
1414
pip install -r requirements/requirements.txt --no-index --find-links ./vendor/

apps/docs/templates/openapi.html

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@
4040

4141
<body>
4242
<div id="swagger-ui"></div>
43+
<button id="custom-logout-button">Logout</button>
4344

4445
<script src="{% static 'swagger-ui-4.15.5-dist/swagger-ui-bundle.js' %}" charset="UTF-8"> </script>
4546
<script src="{% static 'swagger-ui-4.15.5-dist/swagger-ui-standalone-preset.js' %}" charset="UTF-8"> </script>
4647
<script>
4748
window.onload = function() {
48-
const ui = SwaggerUIBundle({
49+
let ui;
50+
ui = SwaggerUIBundle({
4951
urls: [
5052
{
5153
url: "{% static 'openapi.yaml' %}",
@@ -60,13 +62,20 @@
6062
],
6163
layout: "StandaloneLayout",
6264
requestInterceptor: (request) => {
63-
const accessToken = localStorage.getItem('access_token');
64-
if (accessToken) {
65-
request.headers['Authorization'] = `Bearer ${accessToken}`;
65+
if (ui) {
66+
const serverUrl = ui.specSelectors.specJson().toJS().servers[0].url;
67+
const accessToken = localStorage.getItem('access_token');
68+
if (accessToken && request.url.startsWith(serverUrl)) {
69+
request.headers['Authorization'] = `Bearer ${accessToken}`;
70+
}
6671
}
67-
72+
6873
return request;
6974
},
75+
onComplete: function() {
76+
initializeOauthData()
77+
addLogoutButton();
78+
},
7079

7180
oauth2RedirectUrl: window.location.origin + "/docs/oauth2-redirect"
7281
});
@@ -83,14 +92,14 @@
8392
// Save OAuth2 details to localStorage
8493
const serializedData = serializeObject(window.swaggerUIRedirectOauth2)
8594
/**
86-
* swaggerUIRedirectOauth2 contains information regarding oauth2 clientId, clientSecret etc.
95+
* swaggerUIRedirectOauth2 contains information regarding oauth2 clientId, clientSecret etc.
8796
* This will be required by static/oauth2-redirect.html and will be deserialized there
8897
*/
8998
localStorage.setItem('swaggerUIRedirectOauth2', serializedData);
9099
window.dispatchEvent(new Event('storage'));
91-
}
100+
}
92101

93-
function serializeObject(obj) {
102+
function serializeObject(obj) {
94103
const serializedObj = { ...obj };
95104
for (const key in serializedObj) {
96105
if (typeof serializedObj[key] === 'function') {
@@ -100,13 +109,77 @@
100109
return JSON.stringify(serializedObj);
101110
}
102111

112+
function deserializeObject(serialized) {
113+
const parsedObj = JSON.parse(serialized);
114+
for (const key in parsedObj) {
115+
if (typeof parsedObj[key] === 'string' && parsedObj[key].startsWith('function')) {
116+
parsedObj[key] = new Function('return ' + parsedObj[key])();
117+
}
118+
}
119+
return parsedObj;
120+
}
121+
103122
// Event listener for authorize button click
104123
document.addEventListener('click', (event) => {
105124
if (event.target && event.target.matches('button.btn.modal-btn.auth.authorize.button')) {
106125
waitForSwaggerUIRedirectOauth2();
107126
}
108127
});
109128

129+
function initializeOauthData() {
130+
const oauth2Data = localStorage.getItem('swaggerUIRedirectOauth2');
131+
if (!oauth2Data) {
132+
return;
133+
}
134+
const oauth2 = deserializeObject(oauth2Data)
135+
const tokenUrl = oauth2.auth.schema.tokenUrl;
136+
const clientId = oauth2.auth.clientId
137+
const clientSecret = oauth2.auth.clientSecret;
138+
const redirectUri = oauth2.redirectUrl
139+
const scopes = oauth2.auth.scopes.join(" ");
140+
ui.initOAuth({
141+
clientId: clientId,
142+
clientSecret: clientSecret,
143+
scopeSeparator: " ",
144+
scopes: scopes
145+
})
146+
}
147+
148+
function addLogoutButton() {
149+
const accessToken = localStorage.getItem('access_token');
150+
if (!accessToken) {
151+
return;
152+
}
153+
154+
const authWrapper = document.querySelector('.auth-wrapper');
155+
if (!authWrapper) {
156+
return;
157+
}
158+
159+
const customButtonsWrapper = document.createElement('div');
160+
customButtonsWrapper.id = 'custom-buttons';
161+
customButtonsWrapper.style.display = 'flex';
162+
customButtonsWrapper.style.alignItems = 'center';
163+
customButtonsWrapper.style.marginLeft = '20px';
164+
165+
const classNames = ['btn', 'modal-btn', 'auth', 'button'];
166+
const logoutButton = document.createElement('button');
167+
168+
logoutButton.id = 'logoutButton';
169+
logoutButton.classList.add(...classNames);
170+
logoutButton.textContent = 'Logout';
171+
logoutButton.style.marginLeft = '10px';
172+
173+
logoutButton.addEventListener('click', function() {
174+
localStorage.removeItem('access_token');
175+
localStorage.removeItem('swaggerUIRedirectOauth2');
176+
logoutButton.style.display = 'none';
177+
});
178+
179+
customButtonsWrapper.appendChild(logoutButton);
180+
authWrapper.parentElement.insertBefore(customButtonsWrapper, authWrapper.nextSibling);
181+
}
182+
110183
};
111184

112185
</script>

apps/integration_tests/selenium_generic.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ def setup_method(self, method):
6565
opt.add_argument("--disable-popup-blocking")
6666
opt.add_argument("--enable-javascript")
6767
opt.add_argument('--allow-insecure-localhost')
68-
# opt.add_argument('--window-size=1920,1080')
6968
opt.add_argument("--whitelisted-ips=''")
7069

7170
self.driver = webdriver.Remote(

apps/logging/request_logger.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,15 @@ def extract_request_data(self, request):
132132
self.standard_log_data["auth_pkce_method"] = request.session["auth_pkce_method"]
133133
except Exception:
134134
self.standard_log_data["auth_pkce_method"] = None
135-
136135
try:
137136
self.standard_log_data["auth_language"] = request.session["auth_language"]
138137
except Exception:
139138
pass
139+
try:
140+
request_headers = getattr(request, "headers")
141+
self.standard_log_data["data_facilitator_end_user"] = request_headers["data_facilitator_end_user"]
142+
except Exception:
143+
pass
140144

141145
self.standard_log_data.update(get_session_auth_flow_trace(request))
142146

apps/logging/tests/test_audit_loggers.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,46 @@ def _request_logger_app_not_exist(self, v2=False):
532532
self.assertEqual(json_rec.get("req_app_name"), "")
533533
self.assertEqual(json_rec.get("req_app_id"), "")
534534

535+
def test_request_logger_data_facilitator_end_user(self):
536+
self._request_logger_data_facilitator_end_user(False)
537+
538+
def test_request_logger_data_facilitator_end_user_v2(self):
539+
self._request_logger_data_facilitator_end_user(True)
540+
541+
def _request_logger_data_facilitator_end_user(self, v2=False):
542+
redirect_uri = "http://localhost"
543+
self._create_user("anna", "123456")
544+
capability_a = self._create_capability("Capability A", [])
545+
capability_b = self._create_capability("Capability B", [])
546+
application = self._create_application(
547+
"an app",
548+
grant_type=Application.GRANT_AUTHORIZATION_CODE,
549+
redirect_uris=redirect_uri,
550+
)
551+
552+
application.scope.add(capability_a, capability_b)
553+
api_ver = "v1" if not v2 else "v2"
554+
555+
request = HttpRequest()
556+
self.client.login(request=request, username="anna", password="123456")
557+
558+
payload = {
559+
"client_id": application.id,
560+
"response_type": "code",
561+
"redirect_uri": redirect_uri,
562+
}
563+
564+
headers = {"DATA-END-USER": "End User App"}
565+
566+
response = self.client.get("/{}/o/authorize/".format(api_ver), data=payload, headers=headers)
567+
568+
self.assertNotEqual(response.status_code, 500)
569+
# assert request logger record exist and app name, app id has expected value ""
570+
request_log_content = get_log_content(self.logger_registry, logging.AUDIT_HHS_AUTH_SERVER_REQ_LOGGER)
571+
self.assertIsNotNone(request_log_content)
572+
json_rec = json.loads(request_log_content)
573+
self.assertEqual(json_rec.get("data_facilitator_end_user"), "End User App")
574+
535575
def test_auth_flow_lang_logger(self, v2=False):
536576
# copy and adapted to test auth flow logger
537577
redirect_uri = "http://localhost"

0 commit comments

Comments
 (0)