aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-04-30 15:03:09 +0200
committerChocobozzz <chocobozzz@cpy.re>2020-05-04 16:21:39 +0200
commitbc90883f1a5e9c4ecb76ae358734b85be515af7f (patch)
tree47d578c1d5a3a95e89f2badfade76b125de11084
parenta4995eb7ac5745f62604d70f7b2225ff33916d49 (diff)
downloadPeerTube-bc90883f1a5e9c4ecb76ae358734b85be515af7f.tar.gz
PeerTube-bc90883f1a5e9c4ecb76ae358734b85be515af7f.tar.zst
PeerTube-bc90883f1a5e9c4ecb76ae358734b85be515af7f.zip
Handle external login errors
-rw-r--r--client/src/app/login/login.component.html10
-rw-r--r--client/src/app/login/login.component.scss9
-rw-r--r--client/src/app/login/login.component.ts7
-rw-r--r--server/lib/auth.ts18
-rw-r--r--server/lib/client-html.ts2
-rw-r--r--server/lib/plugins/register-helpers-store.ts4
-rw-r--r--server/models/server/plugin.ts44
7 files changed, 61 insertions, 33 deletions
diff --git a/client/src/app/login/login.component.html b/client/src/app/login/login.component.html
index b0639d8ca..a935c86c3 100644
--- a/client/src/app/login/login.component.html
+++ b/client/src/app/login/login.component.html
@@ -3,7 +3,11 @@
3 Login 3 Login
4 </div> 4 </div>
5 5
6 <ng-container *ngIf="!isAuthenticatedWithExternalAuth"> 6 <div class="alert alert-danger" i18n *ngIf="externalAuthError">
7 Sorry but there was an issue with the external login process. Please <a routerLink="/about">contact an administrator</a>.
8 </div>
9
10 <ng-container *ngIf="!externalAuthError && !isAuthenticatedWithExternalAuth">
7 <div class="alert alert-info" *ngIf="signupAllowed === false" role="alert"> 11 <div class="alert alert-info" *ngIf="signupAllowed === false" role="alert">
8 <h6 class="alert-heading" i18n> 12 <h6 class="alert-heading" i18n>
9 If you are looking for an account… 13 If you are looking for an account…
@@ -63,8 +67,8 @@
63 <div class="external-login-blocks" *ngIf="getExternalLogins().length !== 0"> 67 <div class="external-login-blocks" *ngIf="getExternalLogins().length !== 0">
64 <div class="block-title" i18n>Or sign in with</div> 68 <div class="block-title" i18n>Or sign in with</div>
65 69
66 <div class="external-login-block"> 70 <div>
67 <a *ngFor="let auth of getExternalLogins()" [href]="getAuthHref(auth)" role="button"> 71 <a class="external-login-block" *ngFor="let auth of getExternalLogins()" [href]="getAuthHref(auth)" role="button">
68 {{ auth.authDisplayName }} 72 {{ auth.authDisplayName }}
69 </a> 73 </a>
70 </div> 74 </div>
diff --git a/client/src/app/login/login.component.scss b/client/src/app/login/login.component.scss
index ccc98c12a..db9f78f7c 100644
--- a/client/src/app/login/login.component.scss
+++ b/client/src/app/login/login.component.scss
@@ -38,7 +38,6 @@ input[type=submit] {
38 } 38 }
39 39
40 .external-login-blocks { 40 .external-login-blocks {
41 padding: 0 10px 10px 10px;
42 min-width: 200px; 41 min-width: 200px;
43 42
44 .block-title { 43 .block-title {
@@ -46,9 +45,12 @@ input[type=submit] {
46 } 45 }
47 46
48 .external-login-block { 47 .external-login-block {
48 @include disable-default-a-behaviour;
49
49 cursor: pointer; 50 cursor: pointer;
50 border: 1px solid #d1d7e0; 51 border: 1px solid #d1d7e0;
51 border-radius: 5px; 52 border-radius: 5px;
53 color: var(--mainForegroundColor);
52 margin: 10px 10px 0 0; 54 margin: 10px 10px 0 0;
53 display: flex; 55 display: flex;
54 justify-content: center; 56 justify-content: center;
@@ -59,11 +61,6 @@ input[type=submit] {
59 &:hover { 61 &:hover {
60 background-color: rgba(209, 215, 224, 0.5) 62 background-color: rgba(209, 215, 224, 0.5)
61 } 63 }
62
63 a {
64 @include disable-default-a-behaviour;
65 color: var(--mainForegroundColor);
66 }
67 } 64 }
68 } 65 }
69} 66}
diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts
index 5db8d3dbb..5d935cb49 100644
--- a/client/src/app/login/login.component.ts
+++ b/client/src/app/login/login.component.ts
@@ -23,7 +23,9 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
23 23
24 error: string = null 24 error: string = null
25 forgotPasswordEmail = '' 25 forgotPasswordEmail = ''
26
26 isAuthenticatedWithExternalAuth = false 27 isAuthenticatedWithExternalAuth = false
28 externalAuthError = false
27 externalLogins: string[] = [] 29 externalLogins: string[] = []
28 30
29 private openedForgotPasswordModal: NgbModalRef 31 private openedForgotPasswordModal: NgbModalRef
@@ -61,6 +63,11 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
61 return 63 return
62 } 64 }
63 65
66 if (snapshot.queryParams.externalAuthError) {
67 this.externalAuthError = true
68 return
69 }
70
64 this.buildForm({ 71 this.buildForm({
65 username: this.loginValidatorsService.LOGIN_USERNAME, 72 username: this.loginValidatorsService.LOGIN_USERNAME,
66 password: this.loginValidatorsService.LOGIN_PASSWORD 73 password: this.loginValidatorsService.LOGIN_PASSWORD
diff --git a/server/lib/auth.ts b/server/lib/auth.ts
index 1fa896f6e..7c1dd1139 100644
--- a/server/lib/auth.ts
+++ b/server/lib/auth.ts
@@ -83,10 +83,13 @@ async function onExternalUserAuthenticated (options: {
83 return 83 return
84 } 84 }
85 85
86 if (!isAuthResultValid(npmName, authName, authResult)) return
87
88 const { res } = authResult 86 const { res } = authResult
89 87
88 if (!isAuthResultValid(npmName, authName, authResult)) {
89 res.redirect('/login?externalAuthError=true')
90 return
91 }
92
90 logger.info('Generating auth bypass token for %s in auth %s of plugin %s.', authResult.username, authName, npmName) 93 logger.info('Generating auth bypass token for %s in auth %s of plugin %s.', authResult.username, authName, npmName)
91 94
92 const bypassToken = await generateRandomString(32) 95 const bypassToken = await generateRandomString(32)
@@ -238,24 +241,27 @@ function proxifyExternalAuthBypass (req: express.Request, res: express.Response)
238 241
239function isAuthResultValid (npmName: string, authName: string, result: RegisterServerAuthenticatedResult) { 242function isAuthResultValid (npmName: string, authName: string, result: RegisterServerAuthenticatedResult) {
240 if (!isUserUsernameValid(result.username)) { 243 if (!isUserUsernameValid(result.username)) {
241 logger.error('Auth method %s of plugin %s did not provide a valid username.', authName, npmName, { result }) 244 logger.error('Auth method %s of plugin %s did not provide a valid username.', authName, npmName, { username: result.username })
242 return false 245 return false
243 } 246 }
244 247
245 if (!result.email) { 248 if (!result.email) {
246 logger.error('Auth method %s of plugin %s did not provide a valid email.', authName, npmName, { result }) 249 logger.error('Auth method %s of plugin %s did not provide a valid email.', authName, npmName, { email: result.email })
247 return false 250 return false
248 } 251 }
249 252
250 // role is optional 253 // role is optional
251 if (result.role && !isUserRoleValid(result.role)) { 254 if (result.role && !isUserRoleValid(result.role)) {
252 logger.error('Auth method %s of plugin %s did not provide a valid role.', authName, npmName, { result }) 255 logger.error('Auth method %s of plugin %s did not provide a valid role.', authName, npmName, { role: result.role })
253 return false 256 return false
254 } 257 }
255 258
256 // display name is optional 259 // display name is optional
257 if (result.displayName && !isUserDisplayNameValid(result.displayName)) { 260 if (result.displayName && !isUserDisplayNameValid(result.displayName)) {
258 logger.error('Auth method %s of plugin %s did not provide a valid display name.', authName, npmName, { result }) 261 logger.error(
262 'Auth method %s of plugin %s did not provide a valid display name.',
263 authName, npmName, { displayName: result.displayName }
264 )
259 return false 265 return false
260 } 266 }
261 267
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts
index 572bd03bd..4a4b0d12f 100644
--- a/server/lib/client-html.ts
+++ b/server/lib/client-html.ts
@@ -119,7 +119,7 @@ export class ClientHtml {
119 // Save locale in cookies 119 // Save locale in cookies
120 res.cookie('clientLanguage', lang, { 120 res.cookie('clientLanguage', lang, {
121 secure: WEBSERVER.SCHEME === 'https', 121 secure: WEBSERVER.SCHEME === 'https',
122 sameSite: true, 122 sameSite: 'none',
123 maxAge: 1000 * 3600 * 24 * 90 // 3 months 123 maxAge: 1000 * 3600 * 24 * 90 // 3 months
124 }) 124 })
125 125
diff --git a/server/lib/plugins/register-helpers-store.ts b/server/lib/plugins/register-helpers-store.ts
index a3ec7ef6a..e337b1cb0 100644
--- a/server/lib/plugins/register-helpers-store.ts
+++ b/server/lib/plugins/register-helpers-store.ts
@@ -230,9 +230,9 @@ export class RegisterHelpersStore {
230 230
231 private buildSettingsManager (): PluginSettingsManager { 231 private buildSettingsManager (): PluginSettingsManager {
232 return { 232 return {
233 getSetting: (name: string) => PluginModel.getSetting(this.plugin.name, this.plugin.type, name), 233 getSetting: (name: string) => PluginModel.getSetting(this.plugin.name, this.plugin.type, name, this.settings),
234 234
235 getSettings: (names: string[]) => PluginModel.getSettings(this.plugin.name, this.plugin.type, names), 235 getSettings: (names: string[]) => PluginModel.getSettings(this.plugin.name, this.plugin.type, names, this.settings),
236 236
237 setSetting: (name: string, value: string) => PluginModel.setSetting(this.plugin.name, this.plugin.type, name, value), 237 setSetting: (name: string, value: string) => PluginModel.setSetting(this.plugin.name, this.plugin.type, name, value),
238 238
diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts
index 83c873c5b..3f88ac26d 100644
--- a/server/models/server/plugin.ts
+++ b/server/models/server/plugin.ts
@@ -1,5 +1,10 @@
1import * as Bluebird from 'bluebird'
2import { FindAndCountOptions, json } from 'sequelize'
1import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' 3import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
2import { getSort, throwIfNotValid } from '../utils' 4import { MPlugin, MPluginFormattable } from '@server/typings/models'
5import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model'
6import { PluginType } from '../../../shared/models/plugins/plugin.type'
7import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model'
3import { 8import {
4 isPluginDescriptionValid, 9 isPluginDescriptionValid,
5 isPluginHomepage, 10 isPluginHomepage,
@@ -7,12 +12,7 @@ import {
7 isPluginTypeValid, 12 isPluginTypeValid,
8 isPluginVersionValid 13 isPluginVersionValid
9} from '../../helpers/custom-validators/plugins' 14} from '../../helpers/custom-validators/plugins'
10import { PluginType } from '../../../shared/models/plugins/plugin.type' 15import { getSort, throwIfNotValid } from '../utils'
11import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model'
12import { FindAndCountOptions, json } from 'sequelize'
13import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model'
14import * as Bluebird from 'bluebird'
15import { MPlugin, MPluginFormattable } from '@server/typings/models'
16 16
17@DefaultScope(() => ({ 17@DefaultScope(() => ({
18 attributes: { 18 attributes: {
@@ -112,7 +112,7 @@ export class PluginModel extends Model<PluginModel> {
112 return PluginModel.findOne(query) 112 return PluginModel.findOne(query)
113 } 113 }
114 114
115 static getSetting (pluginName: string, pluginType: PluginType, settingName: string) { 115 static getSetting (pluginName: string, pluginType: PluginType, settingName: string, registeredSettings: RegisterServerSettingOptions[]) {
116 const query = { 116 const query = {
117 attributes: [ 'settings' ], 117 attributes: [ 'settings' ],
118 where: { 118 where: {
@@ -123,13 +123,23 @@ export class PluginModel extends Model<PluginModel> {
123 123
124 return PluginModel.findOne(query) 124 return PluginModel.findOne(query)
125 .then(p => { 125 .then(p => {
126 if (!p || !p.settings) return undefined 126 if (!p || p.settings === undefined) {
127 const registered = registeredSettings.find(s => s.name === settingName)
128 if (!registered || registered.default === undefined) return undefined
129
130 return registered.default
131 }
127 132
128 return p.settings[settingName] 133 return p.settings[settingName]
129 }) 134 })
130 } 135 }
131 136
132 static getSettings (pluginName: string, pluginType: PluginType, settingNames: string[]) { 137 static getSettings (
138 pluginName: string,
139 pluginType: PluginType,
140 settingNames: string[],
141 registeredSettings: RegisterServerSettingOptions[]
142 ) {
133 const query = { 143 const query = {
134 attributes: [ 'settings' ], 144 attributes: [ 'settings' ],
135 where: { 145 where: {
@@ -140,13 +150,17 @@ export class PluginModel extends Model<PluginModel> {
140 150
141 return PluginModel.findOne(query) 151 return PluginModel.findOne(query)
142 .then(p => { 152 .then(p => {
143 if (!p || !p.settings) return {} 153 const result: { [settingName: string ]: string | boolean } = {}
144 154
145 const result: { [settingName: string ]: string } = {} 155 for (const name of settingNames) {
156 if (!p || p.settings[name] === undefined) {
157 const registered = registeredSettings.find(s => s.name === name)
146 158
147 for (const key of Object.keys(p.settings)) { 159 if (registered?.default !== undefined) {
148 if (settingNames.includes(key)) { 160 result[name] = registered.default
149 result[key] = p.settings[key] 161 }
162 } else {
163 result[name] = p.settings[name]
150 } 164 }
151 } 165 }
152 166