From 14d399968c136f0edb286fec1ab67d9fe2764258 Mon Sep 17 00:00:00 2001 From: Mario Romano Date: Tue, 17 Jan 2017 13:44:39 +0000 Subject: [PATCH] #1406 improve CSRF and CORS errors reporting (#1488) --- .../alfresco-login/i18n/en.json | 48 ++++++++++--------- .../alfresco-login/i18n/it.json | 48 ++++++++++--------- .../src/assets/authentication.service.mock.ts | 18 ++++++- .../alfresco-login.component.spec.ts | 46 ++++++++++++++++++ .../components/alfresco-login.component.ts | 20 +++++++- .../ng2-alfresco-login/src/i18n/en.json | 48 ++++++++++--------- .../ng2-alfresco-login/src/i18n/it.json | 48 ++++++++++--------- 7 files changed, 181 insertions(+), 95 deletions(-) diff --git a/demo-shell-ng2/custom-translation/alfresco-login/i18n/en.json b/demo-shell-ng2/custom-translation/alfresco-login/i18n/en.json index 7c1ef10cd9..e7e1d8223f 100644 --- a/demo-shell-ng2/custom-translation/alfresco-login/i18n/en.json +++ b/demo-shell-ng2/custom-translation/alfresco-login/i18n/en.json @@ -1,26 +1,28 @@ { - "LOGIN": { - "LOGO": "Alfresco", - "LABEL": { - "LOGIN": "Login", - "USERNAME": "Username", - "PASSWORD": "Password", - "REMEMBER": "Remember" - }, - "MESSAGES": { - "USERNAME-REQUIRED": "Required", - "USERNAME-MIN": "Your username needs to be at least 4 characters.", - "PASSWORD-REQUIRED": "Enter your password to sign in", - "LOGIN-ERROR-CREDENTIALS": "You have entered an invalid username or password", - "LOGIN-ERROR-PROVIDERS": "Providers cannot be undefined", - "LOGIN-SUCCESS": "Login successful" - }, - "BUTTON": { - "LOGIN": "SIGN IN" - }, - "ACTION": { - "HELP": "NEED HELP?", - "REGISTER": "REGISTER" + "LOGIN": { + "LOGO": "Alfresco", + "LABEL": { + "LOGIN": "Login", + "USERNAME": "Username", + "PASSWORD": "Password", + "REMEMBER": "Remember" + }, + "MESSAGES": { + "USERNAME-REQUIRED": "Required", + "USERNAME-MIN": "Your username needs to be at least 4 characters.", + "PASSWORD-REQUIRED": "Enter your password to sign in", + "LOGIN-ERROR-CREDENTIALS": "You have entered an invalid username or password", + "LOGIN-ERROR-PROVIDERS": "Providers cannot be undefined", + "LOGIN-SUCCESS": "Login successful", + "LOGIN-ERROR-CORS": "CORS exception, check your server configuration", + "LOGIN-ERROR-CSRF": "CSRF exception, set [disableCsrf]=\"true\" in alfresco-login component" + }, + "BUTTON": { + "LOGIN": "SIGN IN" + }, + "ACTION": { + "HELP": "NEED HELP?", + "REGISTER": "REGISTER" + } } - } } diff --git a/demo-shell-ng2/custom-translation/alfresco-login/i18n/it.json b/demo-shell-ng2/custom-translation/alfresco-login/i18n/it.json index c274b00912..5588ae39dd 100644 --- a/demo-shell-ng2/custom-translation/alfresco-login/i18n/it.json +++ b/demo-shell-ng2/custom-translation/alfresco-login/i18n/it.json @@ -1,25 +1,27 @@ { - "LOGIN": { - "LABEL": { - "LOGIN": "Autenticazione", - "USERNAME": "Nome utente", - "PASSWORD": "Password", - "REMEMBER": "Ricordami" - }, - "MESSAGES": { - "USERNAME-REQUIRED": "Campo obbligatorio", - "USERNAME-MIN": "Inserire un nome utente di minimo 4 caratteri.", - "PASSWORD-REQUIRED": "Campo obbligatorio", - "LOGIN-ERROR-CREDENTIALS": "Nome utente o password non validi", - "LOGIN-ERROR-PROVIDERS": "Providers non può essere nullo", - "LOGIN-SUCCESS": "Login effettuata con successo" - }, - "BUTTON": { - "LOGIN": "Accedi" - }, - "ACTION": { - "HELP": "BISOGNO DI AIUTO?", - "REGISTER": "REGISTRATI" + "LOGIN": { + "LABEL": { + "LOGIN": "Autenticazione", + "USERNAME": "Nome utente", + "PASSWORD": "Password", + "REMEMBER": "Ricordami" + }, + "MESSAGES": { + "USERNAME-REQUIRED": "Campo obbligatorio", + "USERNAME-MIN": "Inserire un nome utente di minimo 4 caratteri.", + "PASSWORD-REQUIRED": "Campo obbligatorio", + "LOGIN-ERROR-CREDENTIALS": "Nome utente o password non validi", + "LOGIN-ERROR-PROVIDERS": "Providers non può essere nullo", + "LOGIN-SUCCESS": "Login effettuata con successo", + "LOGIN-ERROR-CORS": "CORS exception, controlla le configurazioni del tuo server", + "LOGIN-ERROR-CSRF": "CSRF exception, set [disableCsrf]=\"true\" in alfresco-login component" + }, + "BUTTON": { + "LOGIN": "Accedi" + }, + "ACTION": { + "HELP": "BISOGNO DI AIUTO?", + "REGISTER": "REGISTRATI" + } } - } -} \ No newline at end of file +} diff --git a/ng2-components/ng2-alfresco-login/src/assets/authentication.service.mock.ts b/ng2-components/ng2-alfresco-login/src/assets/authentication.service.mock.ts index 6be706a7a9..e51df930fc 100644 --- a/ng2-components/ng2-alfresco-login/src/assets/authentication.service.mock.ts +++ b/ng2-components/ng2-alfresco-login/src/assets/authentication.service.mock.ts @@ -24,8 +24,22 @@ export class AuthenticationMock /*extends AlfrescoAuthenticationService*/ { login(username: string, password: string): Observable { if (username === 'fake-username' && password === 'fake-password') { return Observable.of(true); - } else { - return Observable.throw('Fake server error'); } + + if (username === 'fake-username-CORS-error' && password === 'fake-password') { + return Observable.throw({ + error: { + crossDomain: true, + message: 'ERROR: the network is offline, Origin is not allowed by Access-Control-Allow-Origin' + } + }); + } + + if (username === 'fake-username-CSRF-error' && password === 'fake-password') { + return Observable.throw({message: 'ERROR: Invalid CSRF-token', status: 403}); + } + + return Observable.throw('Fake server error'); + } } diff --git a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.spec.ts b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.spec.ts index 6d2b7682c9..b36d04eb0e 100644 --- a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.spec.ts +++ b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.spec.ts @@ -264,6 +264,52 @@ describe('AlfrescoLogin', () => { expect(element.querySelector('#login-error').innerText).toEqual('LOGIN.MESSAGES.LOGIN-ERROR-CREDENTIALS'); }); + it('should return CORS error when server CORS error occurs', () => { + component.providers = 'ECM'; + expect(component.success).toBe(false); + expect(component.error).toBe(false); + + usernameInput.value = 'fake-username-CORS-error'; + passwordInput.value = 'fake-password'; + + usernameInput.dispatchEvent(new Event('input')); + passwordInput.dispatchEvent(new Event('input')); + + fixture.detectChanges(); + + element.querySelector('button').click(); + + fixture.detectChanges(); + + expect(component.error).toBe(true); + expect(component.success).toBe(false); + expect(element.querySelector('#login-error')).toBeDefined(); + expect(element.querySelector('#login-error').innerText).toEqual('LOGIN.MESSAGES.LOGIN-ERROR-CORS'); + }); + + it('should return CSRF error when server CSRF error occurs', () => { + component.providers = 'ECM'; + expect(component.success).toBe(false); + expect(component.error).toBe(false); + + usernameInput.value = 'fake-username-CSRF-error'; + passwordInput.value = 'fake-password'; + + usernameInput.dispatchEvent(new Event('input')); + passwordInput.dispatchEvent(new Event('input')); + + fixture.detectChanges(); + + element.querySelector('button').click(); + + fixture.detectChanges(); + + expect(component.error).toBe(true); + expect(component.success).toBe(false); + expect(element.querySelector('#login-error')).toBeDefined(); + expect(element.querySelector('#login-error').innerText).toEqual('LOGIN.MESSAGES.LOGIN-ERROR-CSRF'); + }); + it('should emit onSuccess event after the login has succeeded', () => { spyOn(component.onSuccess, 'emit'); component.providers = 'ECM'; diff --git a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.ts b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.ts index 17095592ce..05e2755115 100644 --- a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.ts +++ b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.ts @@ -157,8 +157,8 @@ export class AlfrescoLoginComponent implements OnInit { this.onSuccess.emit({token: token, username: values.username, password: values.password}); }, (err: any) => { + this.displayErrorMessage(err); this.enableError(); - this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ERROR-CREDENTIALS'; this.onError.emit(err); this.logService.error(err); }, @@ -166,6 +166,24 @@ export class AlfrescoLoginComponent implements OnInit { ); } + /** + * Check and display the right error message in the UI + */ + private displayErrorMessage(err: any): void { + if (err.error && err.error.crossDomain && err.error.message.indexOf('the network is offline, Origin is not allowed by' + + ' Access-Control-Allow-Origin') > 0) { + this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ERROR-CORS'; + return; + } + + if (err.status === 403 && err.message.indexOf('Invalid CSRF-token') > 0) { + this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ERROR-CSRF'; + return; + } + + this.errorMsg = 'LOGIN.MESSAGES.LOGIN-ERROR-CREDENTIALS'; + } + /** * Check the require parameter * @returns {boolean} diff --git a/ng2-components/ng2-alfresco-login/src/i18n/en.json b/ng2-components/ng2-alfresco-login/src/i18n/en.json index 7c1ef10cd9..e7e1d8223f 100644 --- a/ng2-components/ng2-alfresco-login/src/i18n/en.json +++ b/ng2-components/ng2-alfresco-login/src/i18n/en.json @@ -1,26 +1,28 @@ { - "LOGIN": { - "LOGO": "Alfresco", - "LABEL": { - "LOGIN": "Login", - "USERNAME": "Username", - "PASSWORD": "Password", - "REMEMBER": "Remember" - }, - "MESSAGES": { - "USERNAME-REQUIRED": "Required", - "USERNAME-MIN": "Your username needs to be at least 4 characters.", - "PASSWORD-REQUIRED": "Enter your password to sign in", - "LOGIN-ERROR-CREDENTIALS": "You have entered an invalid username or password", - "LOGIN-ERROR-PROVIDERS": "Providers cannot be undefined", - "LOGIN-SUCCESS": "Login successful" - }, - "BUTTON": { - "LOGIN": "SIGN IN" - }, - "ACTION": { - "HELP": "NEED HELP?", - "REGISTER": "REGISTER" + "LOGIN": { + "LOGO": "Alfresco", + "LABEL": { + "LOGIN": "Login", + "USERNAME": "Username", + "PASSWORD": "Password", + "REMEMBER": "Remember" + }, + "MESSAGES": { + "USERNAME-REQUIRED": "Required", + "USERNAME-MIN": "Your username needs to be at least 4 characters.", + "PASSWORD-REQUIRED": "Enter your password to sign in", + "LOGIN-ERROR-CREDENTIALS": "You have entered an invalid username or password", + "LOGIN-ERROR-PROVIDERS": "Providers cannot be undefined", + "LOGIN-SUCCESS": "Login successful", + "LOGIN-ERROR-CORS": "CORS exception, check your server configuration", + "LOGIN-ERROR-CSRF": "CSRF exception, set [disableCsrf]=\"true\" in alfresco-login component" + }, + "BUTTON": { + "LOGIN": "SIGN IN" + }, + "ACTION": { + "HELP": "NEED HELP?", + "REGISTER": "REGISTER" + } } - } } diff --git a/ng2-components/ng2-alfresco-login/src/i18n/it.json b/ng2-components/ng2-alfresco-login/src/i18n/it.json index c274b00912..5588ae39dd 100644 --- a/ng2-components/ng2-alfresco-login/src/i18n/it.json +++ b/ng2-components/ng2-alfresco-login/src/i18n/it.json @@ -1,25 +1,27 @@ { - "LOGIN": { - "LABEL": { - "LOGIN": "Autenticazione", - "USERNAME": "Nome utente", - "PASSWORD": "Password", - "REMEMBER": "Ricordami" - }, - "MESSAGES": { - "USERNAME-REQUIRED": "Campo obbligatorio", - "USERNAME-MIN": "Inserire un nome utente di minimo 4 caratteri.", - "PASSWORD-REQUIRED": "Campo obbligatorio", - "LOGIN-ERROR-CREDENTIALS": "Nome utente o password non validi", - "LOGIN-ERROR-PROVIDERS": "Providers non può essere nullo", - "LOGIN-SUCCESS": "Login effettuata con successo" - }, - "BUTTON": { - "LOGIN": "Accedi" - }, - "ACTION": { - "HELP": "BISOGNO DI AIUTO?", - "REGISTER": "REGISTRATI" + "LOGIN": { + "LABEL": { + "LOGIN": "Autenticazione", + "USERNAME": "Nome utente", + "PASSWORD": "Password", + "REMEMBER": "Ricordami" + }, + "MESSAGES": { + "USERNAME-REQUIRED": "Campo obbligatorio", + "USERNAME-MIN": "Inserire un nome utente di minimo 4 caratteri.", + "PASSWORD-REQUIRED": "Campo obbligatorio", + "LOGIN-ERROR-CREDENTIALS": "Nome utente o password non validi", + "LOGIN-ERROR-PROVIDERS": "Providers non può essere nullo", + "LOGIN-SUCCESS": "Login effettuata con successo", + "LOGIN-ERROR-CORS": "CORS exception, controlla le configurazioni del tuo server", + "LOGIN-ERROR-CSRF": "CSRF exception, set [disableCsrf]=\"true\" in alfresco-login component" + }, + "BUTTON": { + "LOGIN": "Accedi" + }, + "ACTION": { + "HELP": "BISOGNO DI AIUTO?", + "REGISTER": "REGISTRATI" + } } - } -} \ No newline at end of file +}