mirror of https://github.com/rancher/dashboard.git
245 lines
5.8 KiB
JavaScript
245 lines
5.8 KiB
JavaScript
import { parse as setCookieParser } from 'set-cookie-parser';
|
|
import { randomStr } from '@/utils/string';
|
|
import { parse as parseUrl, removeParam, addParam, addParams } from '@/utils/url';
|
|
import { findBy, addObjects } from '@/utils/array';
|
|
import {
|
|
BACK_TO, SPA, AUTH_TEST, _FLAGGED, GITHUB_SCOPE, GITHUB_NONCE, GITHUB_REDIRECT
|
|
} from '@/config/query-params';
|
|
import { BASE_SCOPES } from '@/store/github';
|
|
|
|
const KEY = 'rc_nonce';
|
|
|
|
const ERR_NONCE = 'nonce';
|
|
const ERR_CLIENT = 'client';
|
|
const ERR_SERVER = 'server';
|
|
|
|
export const state = function() {
|
|
return {
|
|
hasAuth: null,
|
|
loggedIn: false,
|
|
principalId: null,
|
|
};
|
|
};
|
|
|
|
export const getters = {
|
|
enabled(state) {
|
|
return state.hasAuth;
|
|
},
|
|
|
|
loggedIn(state) {
|
|
return state.loggedIn;
|
|
},
|
|
|
|
principalId(state) {
|
|
return state.principalId;
|
|
},
|
|
|
|
isGithub(state) {
|
|
return state.principalId && state.principalId.startsWith('github_user://');
|
|
}
|
|
};
|
|
|
|
export const mutations = {
|
|
hasAuth(state, hasAuth) {
|
|
state.hasAuth = !!hasAuth;
|
|
},
|
|
|
|
loggedInAs(state, principalId) {
|
|
state.loggedIn = true;
|
|
state.principalId = principalId;
|
|
|
|
this.$cookies.remove(KEY);
|
|
},
|
|
|
|
loggedOut(state) {
|
|
// Note: plugin/norman/index watches for this mutation
|
|
// to automatically disconnect subscribe sockets.
|
|
|
|
state.loggedIn = false;
|
|
state.principalId = null;
|
|
},
|
|
};
|
|
|
|
export const actions = {
|
|
getAuthProviders({ dispatch }) {
|
|
return dispatch('rancher/findAll', {
|
|
type: 'authProvider',
|
|
opt: { url: `/v3-public/authProviders`, watch: false }
|
|
}, { root: true });
|
|
},
|
|
|
|
getAuthConfigs({ dispatch }) {
|
|
return dispatch('rancher/findAll', {
|
|
type: 'authConfig',
|
|
opt: { url: `/v3/authConfigs` }
|
|
}, { root: true });
|
|
},
|
|
|
|
async getAuthProvider({ dispatch }, id) {
|
|
const authProviders = await dispatch('getAuthProviders');
|
|
|
|
return findBy(authProviders, 'id', id);
|
|
},
|
|
|
|
async getAuthConfig({ dispatch }, id) {
|
|
const authConfigs = await dispatch('getAuthConfigs');
|
|
|
|
return findBy(authConfigs, 'id', id);
|
|
},
|
|
|
|
async redirectToGithub({ state, commit, dispatch }, opt = {}) {
|
|
let redirectUrl = opt.redirectUrl;
|
|
let route = opt.route;
|
|
|
|
if ( !redirectUrl ) {
|
|
const authProvider = await dispatch('getAuthProvider', 'github');
|
|
|
|
redirectUrl = authProvider.redirectUrl;
|
|
}
|
|
|
|
const nonce = randomStr(16);
|
|
|
|
this.$cookies.set(KEY, nonce, {
|
|
path: '/',
|
|
sameSite: false,
|
|
secure: true,
|
|
});
|
|
|
|
if (!route) {
|
|
route = '/auth/verify';
|
|
}
|
|
|
|
if ( this.$router.options && this.$router.options.base ) {
|
|
const routerBase = this.$router.options.base;
|
|
|
|
if ( routerBase !== '/' ) {
|
|
route = `${ routerBase.replace(/\/+$/, '') }/${ route.replace(/^\/+/, '') }`;
|
|
}
|
|
}
|
|
|
|
let returnToUrl = `${ window.location.origin }${ route }`;
|
|
|
|
const parsed = parseUrl(window.location.href);
|
|
|
|
if ( parsed.query.spa !== undefined ) {
|
|
returnToUrl = addParam(returnToUrl, SPA, _FLAGGED);
|
|
}
|
|
|
|
if ( opt.test ) {
|
|
returnToUrl = addParam(returnToUrl, AUTH_TEST, _FLAGGED);
|
|
}
|
|
|
|
if ( opt.backTo ) {
|
|
returnToUrl = addParam(returnToUrl, BACK_TO, opt.backTo);
|
|
}
|
|
|
|
const fromQuery = unescape(parseUrl(redirectUrl).query?.[GITHUB_SCOPE] || '');
|
|
const scopes = fromQuery.split(/[, ]+/).filter(x => !!x);
|
|
|
|
addObjects(scopes, BASE_SCOPES);
|
|
|
|
if ( opt.scopes ) {
|
|
addObjects(scopes, opt.scopes);
|
|
}
|
|
|
|
let url = removeParam(redirectUrl, GITHUB_SCOPE);
|
|
|
|
url = addParams(url, {
|
|
[GITHUB_SCOPE]: scopes.join(','),
|
|
[GITHUB_REDIRECT]: returnToUrl,
|
|
[GITHUB_NONCE]: nonce
|
|
});
|
|
|
|
if ( opt.redirect === false ) {
|
|
return url;
|
|
} else {
|
|
window.location.href = url;
|
|
}
|
|
},
|
|
|
|
verifyGithub({ dispatch }, { nonce, code }) {
|
|
const expect = this.$cookies.get(KEY, { parseJSON: false });
|
|
|
|
if ( !expect || expect !== nonce ) {
|
|
return ERR_NONCE;
|
|
}
|
|
|
|
return dispatch('login', {
|
|
provider: 'github',
|
|
body: { code }
|
|
});
|
|
},
|
|
|
|
async testGithub({ dispatch }, { nonce, code, config }) {
|
|
const expect = this.$cookies.get(KEY, { parseJSON: false });
|
|
|
|
if ( !expect || expect !== nonce ) {
|
|
return ERR_NONCE;
|
|
}
|
|
|
|
const authConfig = await dispatch('getAuthConfig', 'github');
|
|
|
|
await authConfig.doAction('testAndApply', {
|
|
code,
|
|
enabled: true,
|
|
githubConfig: config
|
|
});
|
|
},
|
|
|
|
async login({ dispatch }, { provider, body }) {
|
|
const authProvider = await dispatch('getAuthProvider', provider);
|
|
|
|
try {
|
|
const res = await authProvider.doAction('login', {
|
|
description: 'Dashboard UI session',
|
|
responseType: 'cookie',
|
|
ttl: 16 * 60 * 60 * 1000,
|
|
...body
|
|
}, { redirectUnauthorized: false });
|
|
|
|
if ( process.server ) {
|
|
const parsed = setCookieParser(res._headers['set-cookie'] || []);
|
|
|
|
for ( const opt of parsed ) {
|
|
const key = opt.name;
|
|
const value = opt.value;
|
|
|
|
delete opt.name;
|
|
delete opt.value;
|
|
|
|
opt.encode = x => x;
|
|
opt.sameSite = false;
|
|
|
|
this.$cookies.set(key, value, opt);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
} catch (err) {
|
|
if ( err._status >= 400 && err._status <= 499 ) {
|
|
return Promise.reject(ERR_CLIENT);
|
|
}
|
|
|
|
return Promise.reject(ERR_SERVER);
|
|
}
|
|
},
|
|
|
|
async logout({ dispatch, commit }, clearToken = true) {
|
|
if ( clearToken !== false ) {
|
|
try {
|
|
await dispatch('rancher/request', {
|
|
url: '/v3/tokens?action=logout',
|
|
method: 'post',
|
|
data: {},
|
|
headers: { 'Content-Type': 'application/json' },
|
|
logoutOnError: false,
|
|
}, { root: true });
|
|
} catch (e) {
|
|
}
|
|
}
|
|
|
|
commit('loggedOut');
|
|
dispatch('onLogout', null, { root: true });
|
|
}
|
|
};
|