1import api, { isPasswordExpired } from '@/store/api'; 2import Cookies from 'js-cookie'; 3import router from '@/router'; 4import { roles } from '@/router/routes'; 5 6const AuthenticationStore = { 7 namespaced: true, 8 state: { 9 consoleWindow: null, 10 authError: false, 11 xsrfCookie: Cookies.get('XSRF-TOKEN'), 12 isAuthenticatedCookie: Cookies.get('IsAuthenticated'), 13 sessionURI: localStorage.getItem('sessionURI'), 14 xAuthToken: null, 15 }, 16 getters: { 17 consoleWindow: (state) => state.consoleWindow, 18 authError: (state) => state.authError, 19 isLoggedIn: (state) => { 20 // We might have gotten XSRF-TOKEN (and HttpOnly SESSION cookie) by Mutual TLS authentication, 21 // without going through explicit Session creation 22 return ( 23 state.xsrfCookie !== undefined || 24 state.isAuthenticatedCookie == 'true' || 25 state.xAuthToken !== null 26 ); 27 }, 28 // Used to authenticate WebSocket connections via subprotocol value 29 token: (state) => state.xsrfCookie, 30 }, 31 mutations: { 32 authSuccess(state, { session, token }) { 33 state.authError = false; 34 state.xsrfCookie = Cookies.get('XSRF-TOKEN'); 35 // Preserve session data across page reloads and browser restarts 36 localStorage.setItem('sessionURI', session); 37 state.sessionURI = session; 38 // If we didn't get the XSRF cookie it means we are talking to a 39 // Redfish implementation that is not bmcweb. In this case get the token 40 // from headers and send it with the future requests, do not permanently 41 // save anywhere. 42 if (state.xsrfCookie === undefined) { 43 api.set_auth_token(token); 44 state.xAuthToken = token; 45 } 46 }, 47 authError(state, authError = true) { 48 state.authError = authError; 49 }, 50 logout(state) { 51 Cookies.remove('XSRF-TOKEN'); 52 Cookies.remove('IsAuthenticated'); 53 api.set_auth_token(undefined); 54 localStorage.removeItem('storedUsername'); 55 state.xsrfCookie = undefined; 56 state.isAuthenticatedCookie = undefined; 57 localStorage.removeItem('sessionURI'); 58 state.sessionURI = null; 59 state.xAuthToken = null; 60 state.consoleWindow = false; 61 }, 62 }, 63 actions: { 64 login({ commit }, { username, password }) { 65 commit('authError', false); 66 return api 67 .post('/redfish/v1/SessionService/Sessions', { 68 UserName: username, 69 Password: password, 70 }) 71 .then(({ headers, data }) => { 72 commit('authSuccess', { 73 session: headers['location'], 74 token: headers['x-auth-token'], 75 }); 76 setSessionPrivilege(commit, data); 77 return isPasswordExpired(data); 78 }) 79 .catch((error) => { 80 commit('authError'); 81 throw new Error(error); 82 }); 83 }, 84 logout({ commit, state }) { 85 api 86 .delete(state.sessionURI) 87 .catch(() => 88 console.log( 89 "Couldn't DELETE Session, proceeding with the logout anyway to get in sync with the backend.", 90 ), 91 ) 92 .then(() => commit('logout')) 93 .then(() => router.push('/login')) 94 .catch((error) => console.log(error)); 95 }, 96 getSessionPrivilege({ commit, state }) { 97 return api 98 .get(state.sessionURI) 99 .then(({ data }) => setSessionPrivilege(commit, data)); 100 }, 101 resetStoreState({ state }) { 102 state.authError = false; 103 state.xsrfCookie = Cookies.get('XSRF-TOKEN'); 104 state.isAuthenticatedCookie = Cookies.get('IsAuthenticated'); 105 }, 106 }, 107}; 108 109const setSessionPrivilege = (commit, data) => { 110 // If the backend didn't provide the role information in the Session object 111 // our best bet is to assume the Administrator role to avoid hiding 112 // potentially useful UI elements. Everything security-sensitive is validated 113 // on the backend side anyway, so this is safe. 114 commit('global/setPrivilege', data.Roles?.[0] ?? roles.administrator, { 115 root: true, 116 }); 117}; 118 119export default AuthenticationStore; 120