From e62f6ef741c8d14817e321c554796ad64ea7ae1b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 27 Jul 2016 21:15:13 +0200 Subject: Client: fix login state when logout --- client/src/app/shared/auth/auth.service.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'client/src/app/shared/auth/auth.service.ts') diff --git a/client/src/app/shared/auth/auth.service.ts b/client/src/app/shared/auth/auth.service.ts index 667fbeb1f..4c08e24c0 100644 --- a/client/src/app/shared/auth/auth.service.ts +++ b/client/src/app/shared/auth/auth.service.ts @@ -107,6 +107,8 @@ export class AuthService { // TODO: make an HTTP request to revoke the tokens this.user = null; User.flush(); + + this.setStatus(AuthStatus.LoggedOut); } refreshAccessToken() { -- cgit v1.2.3 From 6606150c49f587bc7eb0ecec4263ce7fbb18bf15 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 5 Aug 2016 16:09:39 +0200 Subject: Server: move clients in its own file --- client/src/app/shared/auth/auth.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'client/src/app/shared/auth/auth.service.ts') diff --git a/client/src/app/shared/auth/auth.service.ts b/client/src/app/shared/auth/auth.service.ts index 4c08e24c0..6a5b19ffe 100644 --- a/client/src/app/shared/auth/auth.service.ts +++ b/client/src/app/shared/auth/auth.service.ts @@ -8,7 +8,7 @@ import { User } from './user.model'; @Injectable() export class AuthService { - private static BASE_CLIENT_URL = '/api/v1/users/client'; + private static BASE_CLIENT_URL = '/api/v1/clients/local'; private static BASE_TOKEN_URL = '/api/v1/users/token'; loginChangedSource: Observable; -- cgit v1.2.3 From 629d8d6f70cf83b55011dff53bfe1c4a95ac3433 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 5 Aug 2016 18:04:08 +0200 Subject: Client: implement password change --- client/src/app/shared/auth/auth.service.ts | 37 +++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'client/src/app/shared/auth/auth.service.ts') diff --git a/client/src/app/shared/auth/auth.service.ts b/client/src/app/shared/auth/auth.service.ts index 6a5b19ffe..24d1a4fa2 100644 --- a/client/src/app/shared/auth/auth.service.ts +++ b/client/src/app/shared/auth/auth.service.ts @@ -10,6 +10,7 @@ import { User } from './user.model'; export class AuthService { private static BASE_CLIENT_URL = '/api/v1/clients/local'; private static BASE_TOKEN_URL = '/api/v1/users/token'; + private static BASE_USER_INFORMATIONS_URL = '/api/v1/users/me'; loginChangedSource: Observable; @@ -99,6 +100,7 @@ export class AuthService { res.username = username; return res; }) + .flatMap(res => this.fetchUserInformations(res)) .map(res => this.handleLogin(res)) .catch(this.handleError); } @@ -136,31 +138,50 @@ export class AuthService { .catch(this.handleError); } - private setStatus(status: AuthStatus) { - this.loginChanged.next(status); + private fetchUserInformations (obj: any) { + // Do not call authHttp here to avoid circular dependencies headaches + + const headers = new Headers(); + headers.set('Authorization', `Bearer ${obj.access_token}`); + + return this.http.get(AuthService.BASE_USER_INFORMATIONS_URL, { headers }) + .map(res => res.json()) + .map(res => { + obj.id = res.id; + obj.role = res.role; + return obj; + } + ); + } + + private handleError (error: Response) { + console.error(error); + return Observable.throw(error.json() || { error: 'Server error' }); } private handleLogin (obj: any) { + const id = obj.id; const username = obj.username; + const role = obj.role; const hash_tokens = { access_token: obj.access_token, token_type: obj.token_type, refresh_token: obj.refresh_token }; - this.user = new User(username, hash_tokens); + this.user = new User(id, username, role, hash_tokens); this.user.save(); this.setStatus(AuthStatus.LoggedIn); } - private handleError (error: Response) { - console.error(error); - return Observable.throw(error.json() || { error: 'Server error' }); - } - private handleRefreshToken (obj: any) { this.user.refreshTokens(obj.access_token, obj.refresh_token); this.user.save(); } + + private setStatus(status: AuthStatus) { + this.loginChanged.next(status); + } + } -- cgit v1.2.3 From 7da18e4420c4b71a8ecfda07f39324fbfec081c3 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 9 Aug 2016 21:45:21 +0200 Subject: Client: add user management --- client/src/app/shared/auth/auth.service.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'client/src/app/shared/auth/auth.service.ts') diff --git a/client/src/app/shared/auth/auth.service.ts b/client/src/app/shared/auth/auth.service.ts index 24d1a4fa2..8eea0c4bf 100644 --- a/client/src/app/shared/auth/auth.service.ts +++ b/client/src/app/shared/auth/auth.service.ts @@ -4,7 +4,7 @@ import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; import { AuthStatus } from './auth-status.model'; -import { User } from './user.model'; +import { AuthUser } from './auth-user.model'; @Injectable() export class AuthService { @@ -17,7 +17,7 @@ export class AuthService { private clientId: string; private clientSecret: string; private loginChanged: Subject; - private user: User = null; + private user: AuthUser = null; constructor(private http: Http) { this.loginChanged = new Subject(); @@ -40,7 +40,7 @@ export class AuthService { ); // Return null if there is nothing to load - this.user = User.load(); + this.user = AuthUser.load(); } getRefreshToken() { @@ -65,10 +65,16 @@ export class AuthService { return this.user.getTokenType(); } - getUser(): User { + getUser(): AuthUser { return this.user; } + isAdmin() { + if (this.user === null) return false; + + return this.user.isAdmin(); + } + isLoggedIn() { if (this.getAccessToken()) { return true; @@ -108,7 +114,7 @@ export class AuthService { logout() { // TODO: make an HTTP request to revoke the tokens this.user = null; - User.flush(); + AuthUser.flush(); this.setStatus(AuthStatus.LoggedOut); } @@ -163,13 +169,13 @@ export class AuthService { const id = obj.id; const username = obj.username; const role = obj.role; - const hash_tokens = { + const hashTokens = { access_token: obj.access_token, token_type: obj.token_type, refresh_token: obj.refresh_token }; - this.user = new User(id, username, role, hash_tokens); + this.user = new AuthUser({ id, username, role }, hashTokens); this.user.save(); this.setStatus(AuthStatus.LoggedIn); -- cgit v1.2.3 From de59c48f5f317018e3f746bbe4a7b7efe00109f2 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 23 Aug 2016 16:54:21 +0200 Subject: Client: centralize http res extraction in a service --- client/src/app/shared/auth/auth.service.ts | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'client/src/app/shared/auth/auth.service.ts') diff --git a/client/src/app/shared/auth/auth.service.ts b/client/src/app/shared/auth/auth.service.ts index 8eea0c4bf..2273048c8 100644 --- a/client/src/app/shared/auth/auth.service.ts +++ b/client/src/app/shared/auth/auth.service.ts @@ -1,10 +1,11 @@ import { Injectable } from '@angular/core'; -import { Headers, Http, Response, URLSearchParams } from '@angular/http'; +import { Headers, Http, URLSearchParams } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; import { AuthStatus } from './auth-status.model'; import { AuthUser } from './auth-user.model'; +import { RestExtractor } from '../rest'; @Injectable() export class AuthService { @@ -19,15 +20,15 @@ export class AuthService { private loginChanged: Subject; private user: AuthUser = null; - constructor(private http: Http) { + constructor(private http: Http, private restExtractor: RestExtractor) { this.loginChanged = new Subject(); this.loginChangedSource = this.loginChanged.asObservable(); // Fetch the client_id/client_secret // FIXME: save in local storage? this.http.get(AuthService.BASE_CLIENT_URL) - .map(res => res.json()) - .catch(this.handleError) + .map(this.restExtractor.extractDataGet) + .catch((res) => this.restExtractor.handleError(res)) .subscribe( result => { this.clientId = result.client_id; @@ -101,14 +102,14 @@ export class AuthService { }; return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options) - .map(res => res.json()) + .map(this.restExtractor.extractDataGet) .map(res => { res.username = username; return res; }) .flatMap(res => this.fetchUserInformations(res)) .map(res => this.handleLogin(res)) - .catch(this.handleError); + .catch((res) => this.restExtractor.handleError(res)); } logout() { @@ -139,9 +140,9 @@ export class AuthService { }; return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options) - .map(res => res.json()) + .map(this.restExtractor.extractDataGet) .map(res => this.handleRefreshToken(res)) - .catch(this.handleError); + .catch((res) => this.restExtractor.handleError(res)); } private fetchUserInformations (obj: any) { @@ -160,11 +161,6 @@ export class AuthService { ); } - private handleError (error: Response) { - console.error(error); - return Observable.throw(error.json() || { error: 'Server error' }); - } - private handleLogin (obj: any) { const id = obj.id; const username = obj.username; -- cgit v1.2.3 From 14ad0c276b4948476d58c82270f2107c8ae5ecd8 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Sat, 1 Oct 2016 09:20:42 +0200 Subject: Client: handle the case when the refreshing token step fails --- client/src/app/shared/auth/auth.service.ts | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'client/src/app/shared/auth/auth.service.ts') diff --git a/client/src/app/shared/auth/auth.service.ts b/client/src/app/shared/auth/auth.service.ts index 2273048c8..e12da0b34 100644 --- a/client/src/app/shared/auth/auth.service.ts +++ b/client/src/app/shared/auth/auth.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; -import { Headers, Http, URLSearchParams } from '@angular/http'; +import { Headers, Http, Response, URLSearchParams } from '@angular/http'; +import { Router } from '@angular/router'; import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; @@ -20,7 +21,11 @@ export class AuthService { private loginChanged: Subject; private user: AuthUser = null; - constructor(private http: Http, private restExtractor: RestExtractor) { + constructor( + private http: Http, + private restExtractor: RestExtractor, + private router: Router + ) { this.loginChanged = new Subject(); this.loginChangedSource = this.loginChanged.asObservable(); @@ -142,7 +147,21 @@ export class AuthService { return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options) .map(this.restExtractor.extractDataGet) .map(res => this.handleRefreshToken(res)) - .catch((res) => this.restExtractor.handleError(res)); + .catch((res: Response) => { + // The refresh token is invalid? + if (res.status === 400 && res.json() && res.json().error === 'invalid_grant') { + console.error('Cannot refresh token -> logout...'); + this.logout(); + this.router.navigate(['/login']); + + return Observable.throw({ + json: '', + text: 'You need to reconnect.' + }); + } + + return this.restExtractor.handleError(res); + }); } private fetchUserInformations (obj: any) { -- cgit v1.2.3 From d86099204c0784d1461936e89589a693f6b768a7 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Sat, 1 Oct 2016 12:19:48 +0200 Subject: Client: add some explanations if we cannot retrieve client oauth credentials --- client/src/app/shared/auth/auth.service.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'client/src/app/shared/auth/auth.service.ts') diff --git a/client/src/app/shared/auth/auth.service.ts b/client/src/app/shared/auth/auth.service.ts index e12da0b34..c57486d9a 100644 --- a/client/src/app/shared/auth/auth.service.ts +++ b/client/src/app/shared/auth/auth.service.ts @@ -41,7 +41,10 @@ export class AuthService { console.log('Client credentials loaded.'); }, error => { - alert(error); + alert( + `Cannot retrieve OAuth Client credentials: ${error.text}. \n` + + 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.' + ); } ); -- cgit v1.2.3