Skip to content
Snippets Groups Projects
Unverified Commit 460dcf79 authored by Marco Emilio "sphakka" Poleggi's avatar Marco Emilio "sphakka" Poleggi
Browse files

Frontend: fix for CORS with dynmaic host probing. K8s: backend uses NodePort. More documentation

parent fbc3a788
No related branches found
No related tags found
No related merge requests found
all:
hosts:
testserver:
ansible_ssh_host: '<your-VM-IP>'
# aliases
tfserver:
testserver:
project-web-sso:
testserver:
ansible_ssh_host: '<your-VM-IP>'
......@@ -20,7 +20,7 @@ spec:
spec:
containers:
- name: backend
image: web-sso-backend:latest
image: <your-Docker-Hub-username>/web-sso-backend:latest
ports:
- containerPort: 8000
# @TODO: declare env from config map
......@@ -37,10 +37,11 @@ kind: Service
metadata:
name: backend-service
spec:
type: NodePort
selector:
app: web-sso
tier: backend
ports:
- port: 8000
targetPort: 8000
type: ClusterIP
nodePort: 30080
......@@ -20,6 +20,20 @@
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 15px;
}
input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}
label {
display: block;
margin-bottom: 5px;
}
.button {
display: inline-block;
......@@ -44,19 +58,29 @@
<body>
<div class="container">
<h1 class="welcome-text">Welcome to Dashboard</h1>
<p>You are successfully logged in!</p>
<p>You are logged in!</p>
<button onclick="logout()" class="button">Logout</button>
<button onclick="unenroll()" class="button">Remove account</button>
<form id="unenrollForm">
<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
</div>
<button type="submit" class="button">Remove account</button>
</form>
</div>
<script>
/* Get email from URL or localStorage (you should implement proper state
management) */
const email = localStorage.getItem('userEmail');
console.log(email);
/* The backend is supposed to run in the same host */
const backendHost = window.location.hostname;
async function logout() {
try {
const response = await fetch('http://localhost:8000/logout', {
const response = await fetch(
'http://' + backendHost + ':8000/logout', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
......@@ -76,15 +100,22 @@
alert('Error during logout. ' + error);
}
}
async function unenroll() {
document.getElementById('unenrollForm').addEventListener(
'submit', async (e) => {
e.preventDefault();
const password = document.getElementById('password').value;
try {
const response = await fetch('http://localhost:8000/unenroll', {
const response = await fetch(
'http://' + backendHost + ':8000/unenroll', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ "email": email }),
});
body: JSON.stringify({ email, password }),
}
);
const data = await response.json();
if (data.status === 'OK:UNENROLLED') {
......@@ -98,6 +129,7 @@
alert('Error during unenroll. ' + error);
}
}
);
</script>
</body>
</html>
......@@ -65,7 +65,7 @@
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<input type="password" id="password" name="password">
</div>
<button type="submit" class="button">Login</button>
</form>
......@@ -73,22 +73,28 @@
</div>
<script>
document.getElementById('loginForm').addEventListener('submit', async (e) => {
document.getElementById('loginForm').addEventListener(
'submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
/* The backend is supposed to run in the same host */
const backendHost = window.location.hostname;
try {
const response = await fetch('http://localhost:8000/login', {
const response = await fetch(
'http://' + backendHost + ':8000/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
}
);
const data = await response.json();
if (data.status === 'OK:LOGGED_IN') {
if (data.status === 'OK:LOGGED_IN' ||
data.status === 'OK:SESSION_EXISTS') {
localStorage.setItem('userEmail', email);
window.location.href = 'dashboard.html';
} else if (data.status === 'OK:NEED_PASSWORD') {
......@@ -100,7 +106,8 @@
} catch (error) {
alert('Error during login. ' + error);
}
});
}
);
</script>
</body>
</html>
......@@ -73,19 +73,24 @@
</div>
<script>
document.getElementById('signupForm').addEventListener('submit', async (e) => {
document.getElementById('signupForm').addEventListener(
'submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
/* The backend is supposed to run in the same host */
const backendHost = window.location.hostname;
try {
const response = await fetch('http://localhost:8000/enroll', {
const response = await fetch(
'http://' + backendHost + ':8000/enroll', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
}
);
const data = await response.json();
if (data.status === 'OK:ENROLLED') {
......@@ -97,7 +102,8 @@
} catch (error) {
alert('Error during sign up. ' + error);
}
});
}
);
</script>
</body>
</html>
......@@ -357,8 +357,12 @@ map:
version you developed in
[Lab-Ansible](https://gitedu.hesge.ch/lsds/teaching/bachelor/cloud-and-deployment/lab-ansible)
Task #10, to (commit all related files in directory `Ansible/`):
- expose the application portal's IP (i.e, the load-balancer's) to the
Internet via `socat` or other mechanism of your choice;
- expose the following IPs to the Internet via `socat` or other
mechanism of your choice;
+ the application portal's IP (i.e, the load-balancer's). Port
forwarding: 3000 (internal) -> 80 (external);
+ the backend node's IP. Port forwarding: 30080 (internal *NodePort*)
-> 8000 (external);
- rebuild and push the application images to your Docker Hub
repository. These shall be [`local_action`
tasks.](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_delegation.html)
......@@ -490,6 +494,11 @@ $ make -s docker-push
You can manage your containers with the other make commands: dstop, dstart,
drm, etc.
:alert: To avoid [CORS-related
errors](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors) when
connecting to the application portal, make sure to point your browser to the URL
'http://localhost:3000'.
#### Kubernetes
......@@ -511,6 +520,27 @@ Of course, once all files are ready, any related operations shall be handled
by Ansible. Specifically, a change in the ConfigMap shall trigger a back-end
service redeployment.
:bulb: You may notice that the backend deployment service is of type
'NodePort': that allows the KinD worker node (IP like '172.x.x.x') to expose a
port (by default '30080') that shall be forwarded (e.g., via `socat`) to the
port expected by the frontend ('8000'). :alert: **Without the port forwarding,
the frontend will not be able to connect to the backend!**
Example. After deploying the backend, get the worker node's IP:
``` shell
VM$ kubectl get node/kind-worker -o jsonpath='{.status.addresses[0].address}'
172.18.0.3
```
Then get the backend service's NodePort:
``` shell
VM$ kubectl get service/backend-service -o jsonpath='{.spec.ports[0].nodePort}'
30080
```
Finally, expose the backend IP with port forwarding:
``` shell
VM$ nohup sudo socat -ly tcp-listen:8000,reuseaddr,fork tcp:172.18.0.3:30080 &
```
:bulb: For better security, you may use a K8s Secret manifest instead of the
ConfigMap. This would be a **bonus**.
......@@ -552,4 +582,3 @@ The following tests shall be passed by your implementation:
9. Logout an enrolled user:
* with an active session: shall succeed
* without an active session: shall fail
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment