SAML; Dashboard
This commit is contained in:
62
app/assets/app/auth/MFADisable.component.js
Normal file
62
app/assets/app/auth/MFADisable.component.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Component } from '../../lib/vues6/vues6.js'
|
||||
import { session } from '../service/Session.service.js'
|
||||
import { location_service } from '../service/Location.service.js'
|
||||
import { auth_api } from '../service/AuthApi.service.js'
|
||||
|
||||
const template = `
|
||||
<div class="coreid-auth-page col-lg-6 col-md-8 col-sm-10 col-xs-12 offset-lg-3 offset-md-2 offset-sm-1 offset-xs-0 text-left">
|
||||
<div class="coreid-auth-page-inner">
|
||||
<div class="coreid-header font-weight-light">{{ app_name }}</div>
|
||||
<span v-if="step === 0">
|
||||
<div class="coreid-message">
|
||||
This process will disable multi-factor authentication on your account.
|
||||
<br><br>
|
||||
For security reasons, this will sign you out of all devices. It will also deactivate any existing app passwords you have generated.
|
||||
<br><br>
|
||||
Are you sure you want to continue?
|
||||
</div>
|
||||
<div v-if="error_message" class="error-message">{{ error_message }}</div>
|
||||
<div v-if="other_message" class="other-message">{{ other_message }}</div>
|
||||
<div class="buttons text-right pad-top">
|
||||
<button type="button" class="btn btn-primary" @click="back_click">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" @click="continue_click">Disable MFA</button>
|
||||
</div>
|
||||
</span>
|
||||
<div class="coreid-loading-spinner" v-if="loading"><div class="inner"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
export default class MFADisableComponent extends Component {
|
||||
static get selector() { return 'coreid-mfa-disable-page' }
|
||||
static get template() { return template }
|
||||
static get props() { return [] }
|
||||
|
||||
app_name = ''
|
||||
step = 0
|
||||
loading = false
|
||||
error_message = ''
|
||||
other_message = ''
|
||||
|
||||
vue_on_create() {
|
||||
this.app_name = session.get('app.name')
|
||||
console.log({session})
|
||||
}
|
||||
|
||||
async back_click() {
|
||||
this.loading = true
|
||||
await location_service.redirect('/dash/profile', 500)
|
||||
}
|
||||
|
||||
async continue_click() {
|
||||
this.loading = true
|
||||
const success = await auth_api.mfa_disable()
|
||||
if ( success ) {
|
||||
this.other_message = 'MFA was successfully disabled. You\'ll now sign-in normally.'
|
||||
await location_service.redirect('/dash/profile', 3000)
|
||||
} else {
|
||||
this.error_message = 'An unknown error occurred while trying to disable MFA. Let\'s try again...'
|
||||
await location_service.reload(4000)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ const template = `
|
||||
<div class="coreid-auth-page col-lg-6 col-md-8 col-sm-10 col-xs-12 offset-lg-3 offset-md-2 offset-sm-1 offset-xs-0 text-left">
|
||||
<div class="coreid-auth-page-inner">
|
||||
<div class="coreid-header font-weight-light">{{ app_name }}</div>
|
||||
<div class="coreid-message">{{ message }}</div>
|
||||
<div class="coreid-message" v-html="message"></div>
|
||||
<div class="buttons text-right pad-top">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
168
app/assets/app/auth/PasswordReset.component.js
Normal file
168
app/assets/app/auth/PasswordReset.component.js
Normal file
@@ -0,0 +1,168 @@
|
||||
import { Component } from '../../lib/vues6/vues6.js'
|
||||
import { session } from '../service/Session.service.js'
|
||||
import { location_service } from '../service/Location.service.js'
|
||||
import { password_service } from '../service/Password.service.js'
|
||||
|
||||
const template = `
|
||||
<div class="coreid-auth-page col-lg-6 col-md-8 col-sm-10 col-xs-12 offset-lg-3 offset-md-2 offset-sm-1 offset-xs-0 text-left">
|
||||
<div class="coreid-auth-page-inner">
|
||||
<div class="coreid-header font-weight-light">{{ app_name }}</div>
|
||||
<span v-if="step === 0">
|
||||
<div class="coreid-message">
|
||||
We're going to walk you through resetting your {{ app_name }} password.
|
||||
<span v-if="has_mfa">
|
||||
<br><br>
|
||||
Note that this process will invalidate any existing app passwords you have created.
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
<span v-if="step === 1">
|
||||
<div class="form-group">
|
||||
<label for="coreid-password-reset-input-step-1">Please enter a new password for your account:</label>
|
||||
<input
|
||||
id="coreid-password-reset-input-step-1"
|
||||
type="password"
|
||||
v-model="password"
|
||||
placeholder="New password"
|
||||
class="form-control"
|
||||
@keyup="on_key_up"
|
||||
:disabled="loading"
|
||||
name="password"
|
||||
ref="input_1"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<div class="other-message" v-if="step_1_calc_time">This password would take {{ step_1_calc_time }} to crack.</div>
|
||||
<div class="error-message" v-if="step_1_problem">{{ step_1_problem }}.</div>
|
||||
</div>
|
||||
</span>
|
||||
<span v-if="step === 2">
|
||||
<div class="form-group">
|
||||
<label for="coreid-password-reset-input-step-1">Confirm the password:</label>
|
||||
<input
|
||||
id="coreid-password-reset-input-step-2"
|
||||
type="password"
|
||||
v-model="confirm_password"
|
||||
placeholder="Confirm new password"
|
||||
class="form-control"
|
||||
@keyup="on_key_up"
|
||||
:disabled="loading"
|
||||
name="password_confirmation"
|
||||
ref="input_2"
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
<div v-if="error_message" class="error-message">{{ error_message }}</div>
|
||||
<div v-if="other_message" class="other-message">{{ other_message }}</div>
|
||||
<div class="buttons text-right pad-top">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
@click="back_click"
|
||||
:disabled="loading"
|
||||
>Cancel</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
@click="continue_click"
|
||||
:disabled="loading || (step === 1 && !step_1_valid) || (step === 2 && !step_2_valid)"
|
||||
>{{ step === 2 ? 'Change Password' : 'Continue' }}</button>
|
||||
</div>
|
||||
<div class="coreid-loading-spinner" v-if="loading"><div class="inner"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
export default class PasswordResetComponent extends Component {
|
||||
static get selector() { return 'coreid-password-reset-page' }
|
||||
static get template() { return template }
|
||||
static get props() { return ['app_name'] }
|
||||
|
||||
step = 0
|
||||
loading = false
|
||||
has_mfa = false
|
||||
|
||||
error_message = ''
|
||||
other_message = ''
|
||||
|
||||
step_1_valid = false
|
||||
step_1_calc_time = ''
|
||||
step_1_problem = ''
|
||||
|
||||
step_2_valid = false
|
||||
|
||||
password = ''
|
||||
confirm_password = ''
|
||||
|
||||
vue_on_create() {
|
||||
this.has_mfa = !!session.get('user.has_mfa')
|
||||
}
|
||||
|
||||
async back_click() {
|
||||
this.loading = true
|
||||
this.error_message = this.other_message = ''
|
||||
if ( this.step === 0 ) {
|
||||
await location_service.redirect('/dash/profile', 1500)
|
||||
} else {
|
||||
this.step -= 1
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
async continue_click() {
|
||||
this.loading = true
|
||||
if ( this.step === 0 ) {
|
||||
this.step += 1
|
||||
this.error_message = this.other_message = ''
|
||||
this.loading = false
|
||||
this.$nextTick(() => {
|
||||
this.$refs.input_1.focus()
|
||||
})
|
||||
} else if ( this.step === 1 ) {
|
||||
if ( this.step_1_valid ) {
|
||||
this.step += 1
|
||||
this.error_message = this.other_message = ''
|
||||
this.$nextTick(() => {
|
||||
this.$refs.input_2.focus()
|
||||
})
|
||||
}
|
||||
this.loading = false
|
||||
} else if ( this.step === 2 ) {
|
||||
if ( this.step_2_valid ) {
|
||||
try {
|
||||
await password_service.reset(this.password)
|
||||
this.other_message = 'Your password was reset. For security reasons, you will be asked to sign-in again.'
|
||||
await location_service.redirect('/dash/profile', 5000)
|
||||
} catch (e) {
|
||||
let message = 'An unknown error occurred while attempting to reset your password.'
|
||||
if ( e.response && e.response.data && e.response.data.message ) {
|
||||
message = e.response.data.message
|
||||
}
|
||||
|
||||
this.error_message = message
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
on_key_up(event) {
|
||||
if ( this.step === 1 ) {
|
||||
const result = zxcvbn(this.password)
|
||||
this.step_1_calc_time = result.crack_times_display.offline_slow_hashing_1e4_per_second
|
||||
this.step_1_problem = result.feedback.warning
|
||||
this.step_1_valid = result.score >= 3 // TODO make this configurable
|
||||
} else if ( this.step === 2 ) {
|
||||
this.step_2_valid = this.password === this.confirm_password
|
||||
}
|
||||
|
||||
if ( event.keyCode === 13 ) {
|
||||
// Enter was pressed
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
return this.continue_click()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,9 @@ const template = `
|
||||
|
||||
export default class AuthLoginForm extends Component {
|
||||
static get selector() { return 'coreid-login-form' }
|
||||
static get props() { return ['app_name', 'login_message'] }
|
||||
static get props() { return [
|
||||
'app_name', 'login_message', 'additional_params', 'no_session',
|
||||
] }
|
||||
static get template() { return template }
|
||||
|
||||
username = ''
|
||||
@@ -102,20 +104,23 @@ export default class AuthLoginForm extends Component {
|
||||
this.loading = true
|
||||
this.error_message = ''
|
||||
|
||||
const result = await auth_api.attempt({
|
||||
let attempt_vars = {
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
create_session: true, // TODO support this being passed in
|
||||
})
|
||||
create_session: !this.no_session,
|
||||
}
|
||||
|
||||
if ( typeof this.additional_params === 'object' ) {
|
||||
attempt_vars = {...attempt_vars, ...this.additional_params}
|
||||
}
|
||||
|
||||
const result = await auth_api.attempt(attempt_vars)
|
||||
if ( !result.success ) {
|
||||
this.error_message = result.message || 'Sorry, an unknown error has occurred and we are unable to continue at this time.'
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
|
||||
// TODO handle 2FA
|
||||
|
||||
this.other_message = 'Success! Let\'s get you on your way...'
|
||||
await location_service.redirect(result.next, 1500)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user