mirror of https://github.com/rancher/dashboard.git
Update auth-setup page to handle resetting user password
rancher/dashboard#3143
This commit is contained in:
parent
92c292aa71
commit
999a0bff25
|
|
@ -2548,7 +2548,7 @@ probe:
|
|||
placeholder: Select a check type
|
||||
|
||||
project:
|
||||
members:
|
||||
members:
|
||||
label: Members
|
||||
user: User
|
||||
role: Role
|
||||
|
|
@ -3098,26 +3098,24 @@ servicesPage:
|
|||
label: Service Type
|
||||
|
||||
setup:
|
||||
welcome: Welcome to {vendor}!
|
||||
setPassword: The first order of business is to set a strong password for the default <code>admin</code> user. We suggest using this random one generated just for you, but enter your own if you like.
|
||||
newPassword: New Password
|
||||
confirmPassword: Confirm New Password
|
||||
useRandom: Use a randomly generated password
|
||||
useManual: Set a specific password to use
|
||||
defaultPasswordError: It looks like this is your first time visting the Rancher UI, but the local admin account password is already set to something unique. Log in with that account below to continue the setup process.
|
||||
telemetry:
|
||||
label: Allow collection of anonymous statistics to help us improve Rancher
|
||||
tip: 'Rancher Labs would like to collect a bit of anonymized information
|
||||
about the configuration of your installation to help make Rio better.
|
||||
Your data will not be shared with anyone else, and no information about
|
||||
what specific resources or endpoints you are deploying is included.
|
||||
Once enabled you can view exactly what data will be sent at <code>/v1-telemetry</code>.
|
||||
<a href="https://rancher.com/docs/rancher/v2.x/en/faq/telemetry/" target="_blank" rel="noopener noreferrer nofollow">More Info</a>'
|
||||
eula: I agree to the <a href="https://rancher.com/eula" target="_blank" rel="noopener noreferrer nofollow">terms and conditions</a> for using Rancher.
|
||||
newPassword: New Password
|
||||
newUserSetPassword: The first order of business is to set a strong password for <code>{username}</code>. We suggest using this random one generated just for you, but enter your own if you like.
|
||||
serverUrl:
|
||||
label: Server URL
|
||||
tip: What URL should be used for this Rancher installation? All the nodes in your clusters will need to be able to reach this. You can skip setting this for now, and update it later in General Settings>Advanced Settings.
|
||||
skip: Skip
|
||||
tip: What URL should be used for this Rancher installation? All the nodes in your clusters will need to be able to reach this. You can skip setting this for now, and update it later in General Settings>Advanced Settings.
|
||||
setPassword: The first order of business is to set a strong password for the default <code>{username}</code> user. We suggest using this random one generated just for you, but enter your own if you like.
|
||||
telemetry:
|
||||
label: Allow collection of anonymous statistics to help us improve Rancher
|
||||
tip: >-
|
||||
Rancher Labs would like to collect a bit of anonymized information about the configuration of your installation to help make Rio better. Your data will not be shared with anyone else, and no information about what specific resources or endpoints you are deploying is included. Once enabled you can view exactly what data will be sent at <code>/v1-telemetry</code>. <a href="https://rancher.com/docs/rancher/v2.x/en/faq/telemetry/" target="_blank" rel="noopener noreferrer nofollow">More
|
||||
Info</a>
|
||||
useManual: Set a specific password to use
|
||||
useRandom: Use a randomly generated password
|
||||
welcome: Welcome to {vendor}!
|
||||
|
||||
sortableTable:
|
||||
actionAvailability:
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export const GITHUB_CODE = 'code';
|
|||
export const GITHUB_NONCE = 'state';
|
||||
export const GITHUB_SCOPE = 'scope';
|
||||
export const GITHUB_REDIRECT = 'redirect_uri';
|
||||
export const USERNAME = 'un';
|
||||
|
||||
// General
|
||||
export const _FLAGGED = null; // The value for a key-only flag, like `?desc`
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { applyProducts } from '@/store/type-map';
|
|||
import { findBy } from '@/utils/array';
|
||||
import { ClusterNotFoundError } from '@/utils/error';
|
||||
import { get } from '@/utils/object';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
let beforeEachSetup = false;
|
||||
|
||||
|
|
@ -93,10 +94,10 @@ export default async function({
|
|||
|
||||
if (ok) {
|
||||
if (initialPass) {
|
||||
return redirect({ name: 'auth-setup', query: { [SETUP]: initialPass } });
|
||||
} else {
|
||||
return redirect({ name: 'auth-setup' });
|
||||
store.dispatch('auth/setInitialPass', initialPass);
|
||||
}
|
||||
|
||||
return redirect({ name: 'auth-setup' });
|
||||
} else {
|
||||
const t = store.getters['i18n/t'];
|
||||
|
||||
|
|
@ -125,6 +126,14 @@ export default async function({
|
|||
}
|
||||
|
||||
if ( store.getters['auth/enabled'] !== false && !store.getters['auth/loggedIn'] ) {
|
||||
const v3User = await findV3User(store);
|
||||
|
||||
if (v3User?.mustChangePassword) {
|
||||
store.commit('auth/gotUser', v3User);
|
||||
|
||||
return redirect({ name: 'auth-setup' });
|
||||
}
|
||||
|
||||
// In newer versions the API calls return the auth state instead of having to make a new call all the time.
|
||||
const fromHeader = store.getters['auth/fromHeader'];
|
||||
|
||||
|
|
@ -228,6 +237,15 @@ async function findMe(store) {
|
|||
return me;
|
||||
}
|
||||
|
||||
async function findV3User(store) {
|
||||
const user = await store.dispatch('rancher/findAll', {
|
||||
type: NORMAN.USER,
|
||||
opt: { url: '/v3/users?me=true' }
|
||||
});
|
||||
|
||||
return isEmpty(user[0]) ? {} : user[0];
|
||||
}
|
||||
|
||||
async function tryInitialSetup(store, password = 'admin') {
|
||||
try {
|
||||
const res = await store.dispatch('auth/login', {
|
||||
|
|
|
|||
|
|
@ -11,9 +11,10 @@ import { configType } from '@/models/management.cattle.io.authconfig';
|
|||
import { mapGetters } from 'vuex';
|
||||
import { importLogin } from '@/utils/dynamic-importer';
|
||||
import { _ALL_IF_AUTHED } from '@/plugins/steve/actions';
|
||||
import { MANAGEMENT } from '@/config/types';
|
||||
import { MANAGEMENT, NORMAN } from '@/config/types';
|
||||
import { SETTING } from '@/config/settings';
|
||||
import { LOGIN_ERRORS } from '@/store/auth';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { getVendor, getProduct, setVendor } from '../../config/private-label';
|
||||
|
||||
export default {
|
||||
|
|
@ -190,6 +191,18 @@ export default {
|
|||
password: this.password
|
||||
}
|
||||
});
|
||||
|
||||
const user = await this.$store.dispatch('rancher/findAll', {
|
||||
type: NORMAN.USER,
|
||||
opt: { url: '/v3/users?me=true' }
|
||||
});
|
||||
|
||||
if (!isEmpty(user) && !isEmpty(user[0])) {
|
||||
this.$store.dispatch('auth/gotUser', user[0]);
|
||||
|
||||
this.needsSetup = user[0]?.mustChangePassword ?? false;
|
||||
}
|
||||
|
||||
if ( this.remember ) {
|
||||
this.$cookies.set(USERNAME, this.username, {
|
||||
encode: x => x,
|
||||
|
|
@ -202,7 +215,8 @@ export default {
|
|||
}
|
||||
|
||||
if (this.needsSetup) {
|
||||
this.$router.push({ name: 'auth-setup', query: { setup: this.password } });
|
||||
this.$store.dispatch('auth/setInitialPass', this.password);
|
||||
this.$router.push({ name: 'auth-setup' });
|
||||
} else {
|
||||
this.$router.replace('/');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ export default {
|
|||
}
|
||||
|
||||
const firstLoginSetting = store.getters['management/byId'](MANAGEMENT.SETTING, SETTING.FIRST_LOGIN);
|
||||
const v3User = store.getters['auth/v3User'] ?? {};
|
||||
|
||||
if (firstLoginSetting?.value !== 'true') {
|
||||
if (firstLoginSetting?.value !== 'true' && !v3User?.mustChangePassword) {
|
||||
return redirect('/');
|
||||
}
|
||||
},
|
||||
|
|
@ -51,8 +52,10 @@ export default {
|
|||
}
|
||||
|
||||
const principals = await store.dispatch('rancher/findAll', { type: NORMAN.PRINCIPAL, opt: { url: '/v3/principals' } });
|
||||
const me = findBy(principals, 'me', true);
|
||||
|
||||
const current = route.query[SETUP] || 'admin';
|
||||
const current = route.query[SETUP] || store.getters['auth/initialPass'] || 'admin';
|
||||
const v3User = store.getters['auth/v3User'] ?? {};
|
||||
|
||||
let serverUrl;
|
||||
|
||||
|
|
@ -69,12 +72,15 @@ export default {
|
|||
product: getProduct(),
|
||||
step: parseInt(route.query.step, 10) || 1,
|
||||
|
||||
useRandom: false,
|
||||
haveCurrent: !!current,
|
||||
username: 'admin',
|
||||
useRandom: false,
|
||||
haveCurrent: !!current,
|
||||
username: me?.loginName ?? 'admin',
|
||||
mustChangePassword: v3User?.mustChangePassword ?? false,
|
||||
current,
|
||||
password: '',
|
||||
confirm: '',
|
||||
password: '',
|
||||
confirm: '',
|
||||
|
||||
v3User,
|
||||
|
||||
serverUrl,
|
||||
|
||||
|
|
@ -89,7 +95,7 @@ export default {
|
|||
|
||||
computed: {
|
||||
passwordSubmitDisabled() {
|
||||
if (!this.eula) {
|
||||
if (!this.eula && !this.mustChangePassword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -138,13 +144,15 @@ export default {
|
|||
methods: {
|
||||
async finishPassword(buttonCb) {
|
||||
try {
|
||||
await this.$store.dispatch('loadManagement');
|
||||
if (!this.mustChangePassword) {
|
||||
await this.$store.dispatch('loadManagement');
|
||||
|
||||
await Promise.all([
|
||||
setSetting(this.$store, SETTING.EULA_AGREED, (new Date()).toISOString() ),
|
||||
setSetting(this.$store, SETTING.TELEMETRY, this.telemetry ? 'in' : 'out'),
|
||||
setSetting(this.$store, SETTING.FIRST_LOGIN, 'false'),
|
||||
]);
|
||||
await Promise.all([
|
||||
setSetting(this.$store, SETTING.EULA_AGREED, (new Date()).toISOString() ),
|
||||
setSetting(this.$store, SETTING.TELEMETRY, this.telemetry ? 'in' : 'out'),
|
||||
setSetting(this.$store, SETTING.FIRST_LOGIN, 'false'),
|
||||
]);
|
||||
}
|
||||
|
||||
await this.$store.dispatch('rancher/request', {
|
||||
url: '/v3/users?action=changepassword',
|
||||
|
|
@ -154,8 +162,20 @@ export default {
|
|||
newPassword: this.password
|
||||
},
|
||||
});
|
||||
this.step = 2;
|
||||
buttonCb(true);
|
||||
|
||||
if (this.mustChangePassword) {
|
||||
const user = this.v3User;
|
||||
|
||||
user.mustChangePassword = false;
|
||||
this.$store.dispatch('auth/gotUser', user);
|
||||
|
||||
buttonCb(true);
|
||||
|
||||
this.done();
|
||||
} else {
|
||||
this.step = 2;
|
||||
buttonCb(true);
|
||||
}
|
||||
} catch (err) {
|
||||
buttonCb(false);
|
||||
}
|
||||
|
|
@ -186,9 +206,10 @@ export default {
|
|||
</h1>
|
||||
|
||||
<template v-if="step===1">
|
||||
<p class="text-center mb-40 mt-20 setup-title">
|
||||
<t k="setup.setPassword" :raw="true" />
|
||||
</p>
|
||||
<p
|
||||
class="text-center mb-40 mt-20 setup-title"
|
||||
v-html="t('setup.setPassword', { username }, true)"
|
||||
></p>
|
||||
|
||||
<!-- For password managers... -->
|
||||
<input type="hidden" name="username" autocomplete="username" :value="username" />
|
||||
|
|
@ -218,15 +239,17 @@ export default {
|
|||
label-key="setup.confirmPassword"
|
||||
/>
|
||||
|
||||
<hr class="mt-40 mb-40 " />
|
||||
<div v-if="!mustChangePassword">
|
||||
<hr class="mt-40 mb-40 " />
|
||||
|
||||
<div class="checkbox">
|
||||
<Checkbox v-model="telemetry" :label="t('setup.telemetry.label')" type="checkbox" />
|
||||
<i v-tooltip="{content:t('setup.telemetry.tip', {}, true), delay: {hide:500}, autoHide: false}" class="icon icon-info" />
|
||||
</div>
|
||||
<div class="checkbox pt-10 eula">
|
||||
<Checkbox v-model="eula" type="checkbox" />
|
||||
<span v-html="t('setup.eula', {}, true)"></span>
|
||||
<div class="checkbox">
|
||||
<Checkbox v-model="telemetry" :label="t('setup.telemetry.label')" type="checkbox" />
|
||||
<i v-tooltip="{content:t('setup.telemetry.tip', {}, true), delay: {hide:500}, autoHide: false}" class="icon icon-info" />
|
||||
</div>
|
||||
<div class="checkbox pt-10 eula">
|
||||
<Checkbox v-model="eula" type="checkbox" />
|
||||
<span v-html="t('setup.eula', {}, true)"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-20">
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ export const state = function() {
|
|||
hasAuth: null,
|
||||
loggedIn: false,
|
||||
principalId: null,
|
||||
v3User: null,
|
||||
initialPass: null,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -48,6 +50,14 @@ export const getters = {
|
|||
return state.principalId;
|
||||
},
|
||||
|
||||
v3User(state) {
|
||||
return state.v3User;
|
||||
},
|
||||
|
||||
initialPass(state) {
|
||||
return state.initialPass;
|
||||
},
|
||||
|
||||
isGithub(state) {
|
||||
return state.principalId && state.principalId.startsWith('github_user://');
|
||||
}
|
||||
|
|
@ -58,6 +68,10 @@ export const mutations = {
|
|||
state.fromHeader = fromHeader;
|
||||
},
|
||||
|
||||
gotUser(state, v3User) {
|
||||
state.v3User = v3User;
|
||||
},
|
||||
|
||||
hasAuth(state, hasAuth) {
|
||||
state.hasAuth = !!hasAuth;
|
||||
},
|
||||
|
|
@ -75,7 +89,13 @@ export const mutations = {
|
|||
|
||||
state.loggedIn = false;
|
||||
state.principalId = null;
|
||||
state.v3User = null;
|
||||
state.initialPass = null;
|
||||
},
|
||||
|
||||
initialPass(state, pass) {
|
||||
state.initialPass = pass;
|
||||
}
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
|
|
@ -83,6 +103,14 @@ export const actions = {
|
|||
commit('gotHeader', fromHeader);
|
||||
},
|
||||
|
||||
gotUser({ commit }, user) {
|
||||
commit('gotUser', user);
|
||||
},
|
||||
|
||||
setInitialPass({ commit }, pass) {
|
||||
commit('initialPass', pass);
|
||||
},
|
||||
|
||||
getAuthProviders({ dispatch }) {
|
||||
return dispatch('rancher/findAll', {
|
||||
type: 'authProvider',
|
||||
|
|
|
|||
Loading…
Reference in New Issue