Handle external login errors

This commit is contained in:
Chocobozzz 2020-04-30 15:03:09 +02:00 committed by Chocobozzz
parent a4995eb7ac
commit bc90883f1a
7 changed files with 61 additions and 33 deletions

View File

@ -3,7 +3,11 @@
Login
</div>
<ng-container *ngIf="!isAuthenticatedWithExternalAuth">
<div class="alert alert-danger" i18n *ngIf="externalAuthError">
Sorry but there was an issue with the external login process. Please <a routerLink="/about">contact an administrator</a>.
</div>
<ng-container *ngIf="!externalAuthError && !isAuthenticatedWithExternalAuth">
<div class="alert alert-info" *ngIf="signupAllowed === false" role="alert">
<h6 class="alert-heading" i18n>
If you are looking for an account…
@ -63,8 +67,8 @@
<div class="external-login-blocks" *ngIf="getExternalLogins().length !== 0">
<div class="block-title" i18n>Or sign in with</div>
<div class="external-login-block">
<a *ngFor="let auth of getExternalLogins()" [href]="getAuthHref(auth)" role="button">
<div>
<a class="external-login-block" *ngFor="let auth of getExternalLogins()" [href]="getAuthHref(auth)" role="button">
{{ auth.authDisplayName }}
</a>
</div>

View File

@ -38,7 +38,6 @@ input[type=submit] {
}
.external-login-blocks {
padding: 0 10px 10px 10px;
min-width: 200px;
.block-title {
@ -46,9 +45,12 @@ input[type=submit] {
}
.external-login-block {
@include disable-default-a-behaviour;
cursor: pointer;
border: 1px solid #d1d7e0;
border-radius: 5px;
color: var(--mainForegroundColor);
margin: 10px 10px 0 0;
display: flex;
justify-content: center;
@ -59,11 +61,6 @@ input[type=submit] {
&:hover {
background-color: rgba(209, 215, 224, 0.5)
}
a {
@include disable-default-a-behaviour;
color: var(--mainForegroundColor);
}
}
}
}

View File

@ -23,7 +23,9 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
error: string = null
forgotPasswordEmail = ''
isAuthenticatedWithExternalAuth = false
externalAuthError = false
externalLogins: string[] = []
private openedForgotPasswordModal: NgbModalRef
@ -61,6 +63,11 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
return
}
if (snapshot.queryParams.externalAuthError) {
this.externalAuthError = true
return
}
this.buildForm({
username: this.loginValidatorsService.LOGIN_USERNAME,
password: this.loginValidatorsService.LOGIN_PASSWORD

View File

@ -83,10 +83,13 @@ async function onExternalUserAuthenticated (options: {
return
}
if (!isAuthResultValid(npmName, authName, authResult)) return
const { res } = authResult
if (!isAuthResultValid(npmName, authName, authResult)) {
res.redirect('/login?externalAuthError=true')
return
}
logger.info('Generating auth bypass token for %s in auth %s of plugin %s.', authResult.username, authName, npmName)
const bypassToken = await generateRandomString(32)
@ -238,24 +241,27 @@ function proxifyExternalAuthBypass (req: express.Request, res: express.Response)
function isAuthResultValid (npmName: string, authName: string, result: RegisterServerAuthenticatedResult) {
if (!isUserUsernameValid(result.username)) {
logger.error('Auth method %s of plugin %s did not provide a valid username.', authName, npmName, { result })
logger.error('Auth method %s of plugin %s did not provide a valid username.', authName, npmName, { username: result.username })
return false
}
if (!result.email) {
logger.error('Auth method %s of plugin %s did not provide a valid email.', authName, npmName, { result })
logger.error('Auth method %s of plugin %s did not provide a valid email.', authName, npmName, { email: result.email })
return false
}
// role is optional
if (result.role && !isUserRoleValid(result.role)) {
logger.error('Auth method %s of plugin %s did not provide a valid role.', authName, npmName, { result })
logger.error('Auth method %s of plugin %s did not provide a valid role.', authName, npmName, { role: result.role })
return false
}
// display name is optional
if (result.displayName && !isUserDisplayNameValid(result.displayName)) {
logger.error('Auth method %s of plugin %s did not provide a valid display name.', authName, npmName, { result })
logger.error(
'Auth method %s of plugin %s did not provide a valid display name.',
authName, npmName, { displayName: result.displayName }
)
return false
}

View File

@ -119,7 +119,7 @@ export class ClientHtml {
// Save locale in cookies
res.cookie('clientLanguage', lang, {
secure: WEBSERVER.SCHEME === 'https',
sameSite: true,
sameSite: 'none',
maxAge: 1000 * 3600 * 24 * 90 // 3 months
})

View File

@ -230,9 +230,9 @@ export class RegisterHelpersStore {
private buildSettingsManager (): PluginSettingsManager {
return {
getSetting: (name: string) => PluginModel.getSetting(this.plugin.name, this.plugin.type, name),
getSetting: (name: string) => PluginModel.getSetting(this.plugin.name, this.plugin.type, name, this.settings),
getSettings: (names: string[]) => PluginModel.getSettings(this.plugin.name, this.plugin.type, names),
getSettings: (names: string[]) => PluginModel.getSettings(this.plugin.name, this.plugin.type, names, this.settings),
setSetting: (name: string, value: string) => PluginModel.setSetting(this.plugin.name, this.plugin.type, name, value),

View File

@ -1,5 +1,10 @@
import * as Bluebird from 'bluebird'
import { FindAndCountOptions, json } from 'sequelize'
import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { getSort, throwIfNotValid } from '../utils'
import { MPlugin, MPluginFormattable } from '@server/typings/models'
import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model'
import { PluginType } from '../../../shared/models/plugins/plugin.type'
import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model'
import {
isPluginDescriptionValid,
isPluginHomepage,
@ -7,12 +12,7 @@ import {
isPluginTypeValid,
isPluginVersionValid
} from '../../helpers/custom-validators/plugins'
import { PluginType } from '../../../shared/models/plugins/plugin.type'
import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model'
import { FindAndCountOptions, json } from 'sequelize'
import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model'
import * as Bluebird from 'bluebird'
import { MPlugin, MPluginFormattable } from '@server/typings/models'
import { getSort, throwIfNotValid } from '../utils'
@DefaultScope(() => ({
attributes: {
@ -112,7 +112,7 @@ export class PluginModel extends Model<PluginModel> {
return PluginModel.findOne(query)
}
static getSetting (pluginName: string, pluginType: PluginType, settingName: string) {
static getSetting (pluginName: string, pluginType: PluginType, settingName: string, registeredSettings: RegisterServerSettingOptions[]) {
const query = {
attributes: [ 'settings' ],
where: {
@ -123,13 +123,23 @@ export class PluginModel extends Model<PluginModel> {
return PluginModel.findOne(query)
.then(p => {
if (!p || !p.settings) return undefined
if (!p || p.settings === undefined) {
const registered = registeredSettings.find(s => s.name === settingName)
if (!registered || registered.default === undefined) return undefined
return registered.default
}
return p.settings[settingName]
})
}
static getSettings (pluginName: string, pluginType: PluginType, settingNames: string[]) {
static getSettings (
pluginName: string,
pluginType: PluginType,
settingNames: string[],
registeredSettings: RegisterServerSettingOptions[]
) {
const query = {
attributes: [ 'settings' ],
where: {
@ -140,13 +150,17 @@ export class PluginModel extends Model<PluginModel> {
return PluginModel.findOne(query)
.then(p => {
if (!p || !p.settings) return {}
const result: { [settingName: string ]: string | boolean } = {}
const result: { [settingName: string ]: string } = {}
for (const name of settingNames) {
if (!p || p.settings[name] === undefined) {
const registered = registeredSettings.find(s => s.name === name)
for (const key of Object.keys(p.settings)) {
if (settingNames.includes(key)) {
result[key] = p.settings[key]
if (registered?.default !== undefined) {
result[name] = registered.default
}
} else {
result[name] = p.settings[name]
}
}