Skip to content

Commit

Permalink
Improve the way the plugin authenticates itself against yamcs.
Browse files Browse the repository at this point in the history
Also allow the plugin to work in the case where no authentication agaisnt yamcs server is needed
  • Loading branch information
swarup-n committed Jan 25, 2024
1 parent 45e3830 commit ea29eb1
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 55 deletions.
5 changes: 4 additions & 1 deletion example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ const config = {
"yamcsUserEndpoint": "http://localhost:9000/yamcs-proxy/api/user/",
"yamcsInstance": process.env.YAMCS_INSTANCE,
"yamcsProcessor": "realtime",
"yamcsFolder": process.env.YAMCS_FOLDER
"yamcsFolder": process.env.YAMCS_FOLDER,
"yamcsUsername": process.env.YAMCS_USERNAME,
"yamcsPassword": process.env.YAMCS_PASSWORD,
"yamcsAuthEnabled": process.env.YAMCS_AUTHENTICATION
};
const STATUS_STYLES = {
"NO_STATUS": {
Expand Down
11 changes: 11 additions & 0 deletions src/openmct-yamcs.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import YamcsStalenessProvider from './providers/staleness-provider.js';
import LimitProvider from './providers/limit-provider.js';
import EventLimitProvider from './providers/event-limit-provider.js';
import UserProvider from './providers/user/user-provider.js';
import AuthProvider from './providers/auth.js';

import { faultModelConvertor } from './providers/fault-mgmt-providers/utils.js';
import YamcsFaultProvider from './providers/fault-mgmt-providers/yamcs-fault-provider.js';
Expand All @@ -41,6 +42,16 @@ import ExportToCSVActionPlugin from './actions/exportToCSV/plugin.js';
export default function install(configuration) {
return (openmct) => {
openmct.install(openmct.plugins.ISOTimeFormat());
const authEnabled = configuration.yamcsAuthEnabled && configuration.yamcsAuthEnabled.toLowerCase() === 'true';

if (authEnabled){
const authProvider = new AuthProvider({
openmct,
authEndpoint: configuration.yamcsHistoricalEndpoint,
username: configuration.yamcsUsername,
password: configuration.yamcsPassword
});
}

const latestTelemetryProvider = new LatestTelemetryProvider({
url: configuration.yamcsHistoricalEndpoint,
Expand Down
62 changes: 62 additions & 0 deletions src/providers/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {
getCookie
} from '../utils.js';

export default class AuthProvider {
#openmct;
#username;
#password;
#authEndpoint;
#useRefresh

constructor({openmct, authEndpoint, username, password}) {
console.log(authEndpoint);
this.#openmct = openmct;
this.#username = username;
this.#password = password;
this.#authEndpoint = authEndpoint + "/auth/token";
this.#useRefresh = false;

this.#fetchAccessToken();
}

async #fetchAccessToken() {
const params = new URLSearchParams();

if (this.#useRefresh) {
params.append("refresh_token", getCookie("refresh_token"));
params.append("grant_type", "refresh_token");

} else {
params.append("username", this.#username);
params.append("password", this.#password);
params.append("grant_type", "password");
}

try {
const response = await fetch(this.#authEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params.toString(),
});

if (!response.ok) {
throw new Error(`Failed to retrieve API token: ${response.status}`);
}

const data = await response.json();
document.cookie = `access_token=${data.access_token}; path=/; SameSite=Strict;`;
document.cookie = `refresh_token=${data.refresh_token}; path=/; SameSite=Strict;`;

this.#useRefresh = true;
setTimeout(() => {
this.#fetchAccessToken();
}, 8 * 60 * 1000); // 8 minutes of expiration

} catch (error) {
console.error("Error fetching access token:", error);
}
}
}
67 changes: 13 additions & 54 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,49 +364,6 @@ function flattenObjectArray(array, baseObj = {}) {
}, baseObj);
}

async function getAccessToken(forceRefresh=false) {
const tokenUrl = "http://" + process.env.YAMCS_ENDPOINT + "/auth/token";
const params = new URLSearchParams();

const expiration_time = getCookie("expiration_time");

if (!forceRefresh && expiration_time != null && Date.now() > expiration_time) {
params.append("refresh_token", getCookie("refresh_token"));
params.append("grant_type", "refresh_token");

} else {
params.append("username", process.env.YAMCS_USERNAME);
params.append("password", process.env.YAMCS_PASSWORD);
params.append("grant_type", "password");
}

fetch(tokenUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params.toString(),
})
.then(response => {
if (!response.ok) {
throw new Error(`Failed to retrieve API token: ${response.status}`);
}

return response.json();
})
.then(data => {
const access_token = data.access_token;
const refresh_token = data.refresh_token;

const lastLoginTime = new Date(data.user.lastLoginTime).getTime();
const expires_in = parseInt(data.expires_in) * 1000;

document.cookie = `access_token=${access_token}; path=/; SameSite=Strict;`;
document.cookie = `refresh_token=${refresh_token}; path=/; SameSite=Strict;`;
document.cookie = `expiration_time=${lastLoginTime + expires_in}; path=/; SameSite=Strict;`;
});
}

function getCookie(name) {
const cookies = document.cookie.split(';');
for (const cookie of cookies) {
Expand All @@ -422,23 +379,24 @@ function getCookie(name) {
async function customFetch(url, requestOptions = {}) {
const access_token = getCookie('access_token');

// Extend the provided requestOptions object with headers
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${access_token}`
};
if (access_token != null) {
// Extend the provided requestOptions object with headers
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${access_token}`
};

// Merge the headers with the provided requestOptions headers
requestOptions.headers = {
...requestOptions.headers,
...headers
};
// Merge the headers with the provided requestOptions headers
requestOptions.headers = {
...requestOptions.headers,
...headers
};
}

const response = fetch(url, requestOptions)
.then(response => {
if (!response.ok) {
if (response.status === 401){
getAccessToken(true);
return customFetch(url, requestOptions);
}
else {
Expand All @@ -464,4 +422,5 @@ export {
yieldResults,
getLimitOverrides,
customFetch,
getCookie
};

0 comments on commit ea29eb1

Please sign in to comment.