Merge pull request #391 from Alfresco/dev-mvitale-343

Adapt the Login component to works also with activiti
This commit is contained in:
Mario Romano 2016-07-11 10:11:41 +01:00 committed by GitHub
commit 529ba02ecf
25 changed files with 947 additions and 182 deletions

View File

@ -1 +1,15 @@
<alfresco-login (onSuccess)="onLogin($event)" (onError)="onError($event)"></alfresco-login>
<div style="border-radius: 8px; position: absolute; background-color: papayawhip; color: cadetblue; left: 10px; top: 10px; z-index: 1;">
<p style="width:120px;margin: 20px;">
<label for="switch1" class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input type="checkbox" id="switch1" class="mdl-switch__input" checked (click)="toggleECM(ecm.checked)" #ecm>
<span class="mdl-switch__label">ECM</span>
</label>
</p>
<p style="width:120px;margin: 20px;">
<label for="switch2" class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input type="checkbox" id="switch2" class="mdl-switch__input" (click)="toggleBPM(bpm.checked)" #bpm>
<span class="mdl-switch__label">BPM</span>
</label>
</p>
</div>
<alfresco-login [providers]="providers" (onSuccess)="onLogin($event)" (onError)="onError($event)"></alfresco-login>

View File

@ -33,6 +33,8 @@ export class LoginDemoComponent {
constructor(public router: Router) {
}
providers: string [] = ['ECM'];
onLogin($event) {
console.log($event);
this.router.navigate(['Home']);
@ -42,4 +44,20 @@ export class LoginDemoComponent {
console.log($event);
}
toggleECM(checked) {
if (checked) {
this.providers[0] = 'ECM';
} else {
this.providers[0] = '';
}
}
toggleBPM(checked) {
if (checked) {
this.providers[1] = 'BPM';
} else {
this.providers[1] = '';
}
}
}

View File

@ -22,6 +22,10 @@ import {
ObjectDataTableAdapter
} from 'ng2-alfresco-datatable';
import {
AlfrescoAuthenticationService
} from 'ng2-alfresco-core';
@Component({
selector: 'tasks-demo',
template: `
@ -38,20 +42,22 @@ export class TasksDemoComponent implements OnInit {
tasks: ObjectDataTableAdapter;
constructor(
private activitiService: ActivitiService) {}
private activitiService: ActivitiService,
private auth: AlfrescoAuthenticationService) {}
ngOnInit() {
this.activitiService
.login('denys.vuika@alfresco.com', 'test')
.then(() => {
this.activitiService
.getTasks()
.then((data) => {
let tasks = data || [];
console.log(tasks);
this.loadTasks(tasks);
});
});
if (this.auth.isLoggedIn('BPM')) {
this.activitiService
.getTasks()
.then((data) => {
let tasks = data || [];
console.log(tasks);
this.loadTasks(tasks);
});
} else {
console.error('User unauthorized');
}
}
private loadTasks(tasks: any[]) {

View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;;;;;QAwBU,uBAAuB,EAUvB,sBAAsB,EAItB,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAdvB,qCAAA,uBAAuB,GAAU;gBAC1C,qEAA6B;gBAC7B,uDAAsB;gBACtB,yDAAuB;gBACvB,6DAAyB;gBACzB,+DAA0B;gBAC1B,qDAAqB;gBACrB,yCAAkB;aACrB,CAAA,CAAC;YAEW,oCAAA,sBAAsB,GAAU;gBACzC,yCAAkB;aACrB,CAAA,CAAC;YAEW,qCAAA,uBAAuB,GAAU;gBAC1C,0DAA0B;gBAC1B,6CAAoB;aACvB,CAAA,CAAC"}

View File

@ -0,0 +1,37 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AbstractAuthentication } from '../interface/authentication.interface';
import { AlfrescoAuthenticationBPM } from '../services/AlfrescoAuthenticationBPM.service';
import { AlfrescoAuthenticationECM } from '../services/AlfrescoAuthenticationECM.service';
import { Http } from '@angular/http';
import { AlfrescoSettingsService } from '../services/AlfrescoSettingsService.service';
export class AuthenticationFactory {
public static createAuth(alfrescoSettingsService: AlfrescoSettingsService,
http: Http,
type: string): AbstractAuthentication {
if (type === 'ECM') {
return new AlfrescoAuthenticationECM(alfrescoSettingsService, http);
} else if (type === 'BPM') {
return new AlfrescoAuthenticationBPM(alfrescoSettingsService, http);
}
return null;
}
}

View File

@ -0,0 +1,33 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Observable } from 'rxjs/Rx';
export interface AbstractAuthentication {
TYPE: string;
login(username: string, password: string): Observable<any>;
logout(): Observable<any>;
isLoggedIn(): boolean ;
getToken(): string;
saveToken(): void;
}

View File

@ -0,0 +1,108 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AbstractAuthentication } from '../interface/authentication.interface';
import { Http, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import { AlfrescoAuthenticationBase } from './AlfrescoAuthenticationBase.service';
import { AlfrescoSettingsService } from './AlfrescoSettingsService.service';
export class AlfrescoAuthenticationBPM extends AlfrescoAuthenticationBase implements AbstractAuthentication {
TYPE: string = 'BPM';
private token: string;
constructor(private alfrescoSettingsService: AlfrescoSettingsService,
private http: Http) {
super(alfrescoSettingsService, http);
}
/**
* Perform a login on behalf of the user and store the ticket returned
*
* @param username
* @param password
* @returns {Observable<R>|Observable<T>}
*/
login(username: string, password: string): Observable<any> {
return Observable.fromPromise(this.apiActivitiLogin(username, password))
.map((response: any) => {
this.token = response.status;
return this.token;
// return {name: this.TYPE, token: response.status};
})
.catch(this.handleError);
}
/**
* Delete the current login ticket from the server
*
* @returns {Observable<R>|Observable<T>}
*/
logout() {
return Observable.fromPromise(this.apiActivitiLogout())
.map(res => <any> res)
.do(response => {
this.removeToken(this.TYPE);
})
.catch(this.handleError);
}
/**
* The method return true if the user is logged in
* @returns {boolean}
*/
isLoggedIn(): boolean {
return !!this.getToken();
}
private apiActivitiLogin(username: string, password: string) {
let url = 'http://localhost:9999/activiti-app/app/authentication';
let headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
});
let options = new RequestOptions({headers: headers});
let data = 'j_username='
+ encodeURIComponent(username)
+ '&j_password='
+ encodeURIComponent(password)
+ '&_spring_security_remember_me=true&submit=Login';
return this.http
.post(url, data, options).toPromise();
}
private apiActivitiLogout() {
let url = 'http://localhost:9999/activiti-app/app/logout';
return this.http.get(url).toPromise();
}
public getToken (): string {
return localStorage.getItem(`token-${this.TYPE}`);
}
/**
* The method save the toke in the localStorage
* @param token
*/
public saveToken(): void {
if (this.token) {
super.saveToken(this.TYPE, this.token);
}
}
}

View File

@ -0,0 +1,68 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Http, Response } from '@angular/http';
import { AlfrescoSettingsService } from './AlfrescoSettingsService.service';
import { Observable } from 'rxjs/Rx';
declare let AlfrescoApi: any;
export class AlfrescoAuthenticationBase {
private _authUrl: string = '/alfresco/api/-default-/public/authentication/versions/1';
private alfrescoSetting: AlfrescoSettingsService;
/**
* Constructor
* @param alfrescoSettingsService
*/
constructor(alfrescoSettingsService: AlfrescoSettingsService,
http: Http) {
this.alfrescoSetting = alfrescoSettingsService;
}
getBaseUrl(): string {
return this.alfrescoSetting.host + this._authUrl;
}
/**
* The method save the toke in the localStorage
* @param token
*/
public saveToken(provider:string, token: string): void {
if (token) {
localStorage.setItem(`token-${provider}`, token);
}
}
/**
* Remove the login token from localStorage
*/
public removeToken(provider:string): void {
localStorage.removeItem(`token-${provider}`);
}
/**
* The method write the error in the console browser
* @param error
* @returns {ErrorObservable}
*/
public handleError(error: Response): Observable<any> {
console.error('Error when logging in', error);
return Observable.throw(error || 'Server error');
}
}

View File

@ -0,0 +1,110 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AbstractAuthentication } from '../interface/authentication.interface';
import { Observable } from 'rxjs/Rx';
import { Http } from '@angular/http';
import { AlfrescoAuthenticationBase } from './AlfrescoAuthenticationBase.service';
import { AlfrescoSettingsService } from './AlfrescoSettingsService.service';
declare let AlfrescoApi: any;
export class AlfrescoAuthenticationECM extends AlfrescoAuthenticationBase implements AbstractAuthentication {
TYPE: string = 'ECM';
private token: string;
constructor(private alfrescoSettingsService: AlfrescoSettingsService,
private http: Http) {
super(alfrescoSettingsService, http);
}
/**
* Perform a login on behalf of the user and store the ticket returned
*
* @param username
* @param password
* @returns {Observable<R>|Observable<T>}
*/
login(username: string, password: string): Observable<any> {
return Observable.fromPromise(this.getCreateTicketPromise(username, password))
.map((response: any) => {
this.token = response.entry.id;
return this.token;
// return {name: this.TYPE, token: response.entry.id};
})
.catch(this.handleError);
}
/**
* Delete the current login ticket from the server
*
* @returns {Observable<R>|Observable<T>}
*/
logout() {
return Observable.fromPromise(this.getDeleteTicketPromise())
.map(res => <any> res)
.do(response => {
this.removeToken(this.TYPE);
})
.catch(this.handleError);
}
/**
* The method return true if the user is logged in
* @returns {boolean}
*/
isLoggedIn(): boolean {
return !!this.getToken();
}
private getAlfrescoClient() {
return AlfrescoApi.getClientWithTicket(this.getBaseUrl(), this.getToken());
}
private getCreateTicketPromise(username: string, password: string) {
let apiInstance = new AlfrescoApi.Auth.AuthenticationApi(this.getAlfrescoClient());
let loginRequest = new AlfrescoApi.Auth.LoginRequest();
loginRequest.userId = username;
loginRequest.password = password;
return apiInstance.createTicket(loginRequest);
}
private getDeleteTicketPromise() {
let apiInstance = new AlfrescoApi.Auth.AuthenticationApi(this.getAlfrescoClient());
return apiInstance.deleteTicket();
}
/**
* The method return the token stored in the localStorage
* @param token
*/
public getToken (): string {
return localStorage.getItem(`token-${this.TYPE}`);
}
/**
* The method save the toke in the localStorage
* @param token
*/
public saveToken(): void {
if (this.token) {
super.saveToken(this.TYPE, this.token);
}
}
}

View File

@ -15,21 +15,54 @@
* limitations under the License.
*/
import { it, describe, beforeEach } from '@angular/core/testing';
import { ReflectiveInjector } from '@angular/core';
import { it, describe } from '@angular/core/testing';
import { ReflectiveInjector, provide } from '@angular/core';
import { AlfrescoSettingsService } from './AlfrescoSettingsService.service';
import { AlfrescoAuthenticationService } from './AlfrescoAuthenticationService.service';
import { AlfrescoAuthenticationECM } from './AlfrescoAuthenticationECM.service';
import { AlfrescoAuthenticationBPM } from './AlfrescoAuthenticationBPM.service';
import { XHRBackend, HTTP_PROVIDERS } from '@angular/http';
import { MockBackend } from '@angular/http/testing';
declare var AlfrescoApi: any;
describe('AlfrescoAuthentication', () => {
let injector,
fakePromiseECM,
fakePromiseBPM,
service;
fakePromiseECM = new Promise(function (resolve, reject) {
resolve({
entry: {
userId: 'fake-username',
id: 'fake-post-token-ECM'
}
});
reject({
response: {
error: 'fake-error'
}
});
});
fakePromiseBPM = new Promise(function (resolve, reject) {
resolve({
status: 'fake-post-token-BPM'
});
reject({
response: {
error: 'fake-error'
}
});
});
beforeEach(() => {
injector = ReflectiveInjector.resolveAndCreate([
AlfrescoAuthenticationService,
AlfrescoSettingsService
HTTP_PROVIDERS,
provide(XHRBackend, {useClass: MockBackend}),
provide(AlfrescoSettingsService, {useClass: AlfrescoSettingsService}),
AlfrescoAuthenticationService
]);
let store = {};
@ -54,58 +87,283 @@ describe('AlfrescoAuthentication', () => {
service = injector.get(AlfrescoAuthenticationService);
});
it('should return true and token if the user is logged in', () => {
service.saveToken('fake-local-token');
expect(service.isLoggedIn()).toBe(true);
expect(localStorage.getItem('token')).toBeDefined();
expect(localStorage.getItem('token')).toEqual('fake-local-token');
});
describe('when the setting is ECM', () => {
it('should return false and token undefined if the user is not logged in', () => {
expect(service.isLoggedIn()).toEqual(false);
expect(localStorage.getItem('token')).not.toBeDefined();
it('should create an AlfrescoAuthenticationECM instance', (done) => {
let providers = ['ECM'];
spyOn(AlfrescoAuthenticationECM.prototype, 'getCreateTicketPromise').and.returnValue(fakePromiseECM);
});
it('should return true and token on sign in', () => {
let p = new Promise(function (resolve, reject) {
resolve({
entry: {
userId: 'fake-username',
id: 'fake-post-token'
}
});
});
spyOn(service, 'getCreateTicketPromise').and.returnValue(p);
service.token = '';
service.login('fake-username', 'fake-password')
.subscribe(() => {
expect(service.isLoggedIn()).toBe(true);
expect(service.getToken()).toEqual('fake-post-token');
expect(localStorage.getItem('token')).toBeDefined();
expect(localStorage.getItem('token')).toEqual('fake-post-token');
service.login('fake-username', 'fake-password', providers)
.subscribe(() => {
expect(service.isLoggedIn(providers[0])).toBe(true);
expect(service.providersInstance).toBeDefined();
expect(service.providersInstance.length).toBe(1);
expect(service.providersInstance[0].TYPE).toEqual(providers[0]);
done();
}
);
});
it('should return false and token undefined on log out', () => {
let p = new Promise(function (resolve, reject) {
resolve();
});
spyOn(service, 'getDeleteTicketPromise').and.returnValue(p);
it('should return an ECM token after the login done', (done) => {
let providers = ['ECM'];
spyOn(AlfrescoAuthenticationECM.prototype, 'getCreateTicketPromise').and.returnValue(fakePromiseECM);
localStorage.setItem('token', 'fake-token');
service.logout()
.subscribe(() => {
expect(service.isLoggedIn()).toBe(false);
expect(service.getToken()).toBeUndefined();
expect(localStorage.getItem('token')).toBeUndefined();
service.login('fake-username', 'fake-password', providers)
.subscribe(() => {
expect(service.isLoggedIn(providers[0])).toBe(true);
expect(service.getToken(providers[0])).toEqual('fake-post-token-ECM');
done();
}
);
});
it('should return token undefined when the credentials are wrong', (done) => {
let providers = ['ECM'];
spyOn(AlfrescoAuthenticationECM.prototype, 'getCreateTicketPromise')
.and.returnValue(Promise.reject('fake invalid credentials'));
service.login('fake-wrong-username', 'fake-wrong-password', providers)
.subscribe(
(res) => {
done();
},
(err: any) => {
expect(service.isLoggedIn(providers[0])).toBe(false);
expect(service.getToken(providers[0])).toBeUndefined();
done();
}
);
});
it('should return an error if no provider are defined calling the login', (done) => {
let providers = [];
service.login('fake-username', 'fake-password', providers)
.subscribe(
(res) => {
done();
},
(err: any) => {
expect(err).toBeDefined();
expect(err).toEqual('No providers defined');
done();
}
);
});
it('should return an error if an empty provider are defined calling the login', (done) => {
let providers = [''];
service.login('fake-username', 'fake-password', providers)
.subscribe(
(res) => {
done();
},
(err: any) => {
expect(err).toBeDefined();
expect(err).toEqual('No providers defined');
done();
}
);
});
it('should return a token undefined after logout', (done) => {
let providers = ['ECM'];
localStorage.setItem('token-ECM', 'fake-post-token-ECM');
service.createProviderInstance(providers);
spyOn(AlfrescoAuthenticationECM.prototype, 'getDeleteTicketPromise').and.returnValue(fakePromiseECM);
service.logout()
.subscribe(() => {
expect(service.isLoggedIn(providers[0])).toBe(false);
expect(service.getToken(providers[0])).toBeUndefined();
expect(localStorage.getItem('token-ECM')).toBeUndefined();
done();
}
);
});
it('should return an error if no provider are defined calling the logout', (done) => {
service.logout()
.subscribe(
(res) => {
done();
},
(err: any) => {
expect(err).toBeDefined();
expect(err).toEqual('No providers defined');
done();
}
);
});
it('should return false if the user is not logged in', () => {
let providers = ['ECM'];
expect(service.isLoggedIn(providers[0])).toBe(false);
});
});
describe('when the setting is BPM', () => {
it('should create an AlfrescoAuthenticationBPM instance', (done) => {
let providers = ['BPM'];
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogin').and.returnValue(fakePromiseBPM);
service.login('fake-username', 'fake-password', providers)
.subscribe(() => {
expect(service.isLoggedIn(providers[0])).toBe(true);
expect(service.providersInstance).toBeDefined();
expect(service.providersInstance.length).toBe(1);
expect(service.providersInstance[0].TYPE).toEqual(providers[0]);
done();
}
);
});
it('should return an BPM token after the login done', (done) => {
let providers = ['BPM'];
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogin').and.returnValue(fakePromiseBPM);
service.login('fake-username', 'fake-password', providers)
.subscribe(() => {
expect(service.isLoggedIn(providers[0])).toBe(true);
expect(service.getToken(providers[0])).toEqual('fake-post-token-BPM');
done();
}
);
});
it('should return token undefined when the credentials are wrong', (done) => {
let providers = ['BPM'];
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogin').and.returnValue(Promise.reject('fake invalid credentials'));
service.login('fake-wrong-username', 'fake-wrong-password', providers)
.subscribe(
(res) => {
done();
},
(err: any) => {
expect(service.isLoggedIn(providers[0])).toBe(false);
expect(service.getToken(providers[0])).toBeUndefined();
done();
}
);
});
it('should return a token undefined after logout', (done) => {
let providers = ['BPM'];
localStorage.setItem('token-BPM', 'fake-post-token-BPM');
service.createProviderInstance(providers);
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogout').and.returnValue(fakePromiseBPM);
service.logout()
.subscribe(() => {
expect(service.isLoggedIn(providers[0])).toBe(false);
expect(service.getToken(providers[0])).toBeUndefined();
expect(localStorage.getItem('token-BPM')).toBeUndefined();
done();
}
);
});
it('should throw an error when the logout return error', (done) => {
let providers = ['BPM'];
localStorage.setItem('token-BPM', 'fake-post-token-BPM');
service.createProviderInstance(providers);
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogout').and.returnValue(Promise.reject('fake logout error'));
service.logout()
.subscribe(
(res) => {
done();
},
(err: any) => {
expect(err).toBeDefined();
expect(err.message).toEqual('fake logout error');
expect(localStorage.getItem('token-BPM')).toEqual('fake-post-token-BPM');
done();
}
);
});
});
describe('when the setting is both ECM and BPM ', () => {
it('should create both instances', (done) => {
let providers = ['ECM', 'BPM'];
spyOn(AlfrescoAuthenticationECM.prototype, 'getCreateTicketPromise').and.returnValue(fakePromiseECM);
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogin').and.returnValue(fakePromiseBPM);
service.login('fake-username', 'fake-password', providers)
.subscribe(() => {
expect(service.isLoggedIn(providers[0])).toBe(true);
expect(service.isLoggedIn(providers[1])).toBe(true);
expect(service.providersInstance).toBeDefined();
expect(service.providersInstance.length).toBe(2);
expect(service.providersInstance[0].TYPE).toEqual(providers[0]);
expect(service.providersInstance[1].TYPE).toEqual(providers[1]);
done();
}
);
});
it('should return both ECM and BPM tokens after the login done', (done) => {
let providers = ['ECM', 'BPM'];
spyOn(AlfrescoAuthenticationECM.prototype, 'getCreateTicketPromise').and.returnValue(fakePromiseECM);
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogin').and.returnValue(fakePromiseBPM);
service.login('fake-username', 'fake-password', providers)
.subscribe(() => {
expect(service.isLoggedIn(providers[0])).toBe(true);
expect(service.isLoggedIn(providers[1])).toBe(true);
expect(service.getToken(providers[0])).toEqual('fake-post-token-ECM');
expect(service.getToken(providers[1])).toEqual('fake-post-token-BPM');
done();
}
);
});
it('should return token undefined when the credentials are correct for the ECM login but wrong for the BPM login', (done) => {
let providers = ['ECM', 'BPM'];
spyOn(AlfrescoAuthenticationECM.prototype, 'getCreateTicketPromise').and.returnValue(fakePromiseECM);
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogin').and.returnValue(Promise.reject('fake invalid credentials'));
service.login('fake-username', 'fake-password', providers)
.subscribe(
(res) => {
done();
},
(err: any) => {
expect(service.isLoggedIn(providers[0])).toBe(false);
expect(service.getToken(providers[0])).toBeUndefined();
expect(service.isLoggedIn(providers[1])).toBe(false);
expect(service.getToken(providers[1])).toBeUndefined();
done();
}
);
});
it('should return token undefined when the credentials are correct for the BPM login but wrong for the ECM login', (done) => {
let providers = ['ECM', 'BPM'];
spyOn(AlfrescoAuthenticationECM.prototype, 'getCreateTicketPromise')
.and.returnValue(Promise.reject('fake invalid credentials'));
spyOn(AlfrescoAuthenticationBPM.prototype, 'apiActivitiLogin').and.returnValue(fakePromiseBPM);
service.login('fake-username', 'fake-password', providers)
.subscribe(
(res) => {
done();
},
(err: any) => {
expect(service.isLoggedIn(providers[0])).toBe(false);
expect(service.getToken(providers[0])).toBeUndefined();
expect(service.isLoggedIn(providers[1])).toBe(false);
expect(service.getToken(providers[1])).toBeUndefined();
done();
}
);
});
});
});

View File

@ -17,8 +17,11 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { Response } from '@angular/http';
import { Http } from '@angular/http';
import { AlfrescoSettingsService } from './AlfrescoSettingsService.service';
import { AuthenticationFactory } from '../factory/AuthenticationFactory';
import { AbstractAuthentication } from '../interface/authentication.interface';
import { AlfrescoAuthenticationBase } from './AlfrescoAuthenticationBase.service';
declare let AlfrescoApi: any;
@ -26,31 +29,17 @@ declare let AlfrescoApi: any;
* The AlfrescoAuthenticationService provide the login service and store the token in the localStorage
*/
@Injectable()
export class AlfrescoAuthenticationService {
export class AlfrescoAuthenticationService extends AlfrescoAuthenticationBase {
private _authUrl: string = '/alfresco/api/-default-/public/authentication/versions/1';
private providersInstance: AbstractAuthentication[] = [];
/**
* Constructor
* @param alfrescoSettingsService
*/
constructor(private alfrescoSettingsService: AlfrescoSettingsService) {
}
getBaseUrl(): string {
return this.alfrescoSettingsService.host + this._authUrl;
}
private getAlfrescoClient() {
return AlfrescoApi.getClientWithTicket(this.getBaseUrl(), this.getToken());
}
/**
* The method return tru if the user is logged in
* @returns {boolean}
*/
isLoggedIn(): boolean {
return !!localStorage.getItem('token');
constructor(private alfrescoSettingsService: AlfrescoSettingsService,
private http: Http) {
super(alfrescoSettingsService, http);
}
/**
@ -59,95 +48,153 @@ export class AlfrescoAuthenticationService {
* @param password
* @returns {Observable<R>|Observable<T>}
*/
login(username: string, password: string): Observable<string> {
return this.loginPost(username, password);
login(username: string, password: string, providers: string []): Observable<string> {
localStorage.clear();
if (providers.length === 0) {
return Observable.throw('No providers defined');
} else {
this.createProviderInstance(providers);
return this.performeLogin(username, password);
}
}
/**
* Perform a login on behalf of the user and store the ticket returned
* Perform a login on behalf of the user for the different provider instance
*
* @param username
* @param password
* @returns {Observable<R>|Observable<T>}
*/
loginPost(username: string, password: string) {
return Observable.fromPromise(this.getCreateTicketPromise(username, password))
.map(res => <any> res)
.do(response => {
this.saveToken(response.entry.id);
return this.getToken();
})
.catch(this.handleError);
}
getCreateTicketPromise(username: string, password: string) {
let apiInstance = new AlfrescoApi.Auth.AuthenticationApi(this.getAlfrescoClient());
let loginRequest = new AlfrescoApi.Auth.LoginRequest();
loginRequest.userId = username;
loginRequest.password = password;
return apiInstance.createTicket(loginRequest);
}
/**
* Delete the current login ticket from the server
*
* @returns {Observable<R>|Observable<T>}
*/
loginDelete() {
return Observable.fromPromise(this.getDeleteTicketPromise())
.map(res => <any> res)
.do(response => {
this.removeToken();
this.saveToken('');
})
.catch(this.handleError);
}
getDeleteTicketPromise() {
let apiInstance = new AlfrescoApi.Auth.AuthenticationApi(this.getAlfrescoClient());
return apiInstance.deleteTicket();
}
/**
* Return the token stored in the localStorage
* @param token
*/
public getToken (): string {
return localStorage.getItem('token');
}
/**
* The method save the toke in the localStorage
* @param token
*/
public saveToken(token): void {
if (token) {
localStorage.setItem('token', token);
private performeLogin(username: string, password: string): Observable<any> {
let observableBatch = [];
if (this.providersInstance.length !== 0) {
this.providersInstance.forEach((authInstance) => {
observableBatch.push(authInstance.login(username, password));
});
return Observable.create(observer => {
Observable.forkJoin(observableBatch).subscribe(
(response: any[]) => {
this.performeSaveToken();
/*response.forEach((res) => {
this.performeSaveToken(res.name, res.token);
});*/
observer.next(response);
},
(err: any) => {
observer.error(new Error(err));
});
});
} else {
return Observable.throw('No providers defined');
}
}
/**
* Remove the login token from localStorage
* The method return tru if the user is logged in
* @returns {boolean}
*/
public removeToken(): void {
localStorage.removeItem('token');
isLoggedIn(type: string = 'ECM'): boolean {
let auth: AbstractAuthentication = this.findProviderInstance(type);
if (auth) {
return auth.isLoggedIn();
}
return false;
}
/**
* Return the token stored in the localStorage of the specific provider type
* @param token
*/
public getToken(type: string = 'ECM'): string {
let auth: AbstractAuthentication = this.findProviderInstance(type);
if (auth) {
return auth.getToken();
}
return '';
}
/**
* Save the token calling the method of the specific provider type
* @param providerName
* @param token
*/
private performeSaveToken() {
/* let auth: AbstractAuthentication = this.findProviderInstance(type);
if (auth) {
auth.saveToken();
}
*/
this.providersInstance.forEach((authInstance) => {
authInstance.saveToken();
});
}
/**
* The method remove the token from the local storage
* @returns {Observable<T>}
*/
public logout() {
return this.loginDelete();
public logout(): Observable<string> {
if (this.providersInstance.length === 0) {
return Observable.throw('No providers defined');
} else {
return this.performeLogout();
}
}
/**
* The method write the error in the console browser
* @param error
* @returns {ErrorObservable}
* Perform a logout on behalf of the user for the different provider instance
*
* @param username
* @param password
* @returns {Observable<R>|Observable<T>}
*/
private handleError(error: Response) {
console.error('Error when logging in', error);
return Observable.throw(error || 'Server error');
private performeLogout(): Observable<any> {
let observableBatch = [];
this.providersInstance.forEach((authInstance) => {
observableBatch.push(authInstance.logout());
});
return Observable.create(observer => {
Observable.forkJoin(observableBatch).subscribe(
(response: any[]) => {
observer.next(response);
},
(err: any) => {
observer.error(new Error(err));
});
});
}
/**
* Create the provider instance using a Factory
* @param providers - list of the providers like ECM BPM
*/
public createProviderInstance(providers: string []): void {
if (this.providersInstance.length === 0) {
providers.forEach((provider) => {
let authInstance: AbstractAuthentication = AuthenticationFactory.createAuth(
this.alfrescoSettingsService, this.http, provider);
if (authInstance) {
this.providersInstance.push(authInstance);
}
});
}
}
/**
* Find the provider by type and return it
* @param type
* @returns {AbstractAuthentication}
*/
private findProviderInstance(type: string): AbstractAuthentication {
let auth: AbstractAuthentication = null;
if (this.providersInstance && this.providersInstance.length !== 0) {
this.providersInstance.forEach((provider) => {
if (provider.TYPE === type) {
auth = provider;
}
});
}
return auth;
}
}

View File

@ -20,6 +20,7 @@ import { ReflectiveInjector } from '@angular/core';
import { AlfrescoSettingsService } from './AlfrescoSettingsService.service';
import { AlfrescoAuthenticationService } from './AlfrescoAuthenticationService.service';
import { AlfrescoContentService } from './AlfrescoContentService.service';
import { HTTP_PROVIDERS } from '@angular/http';
describe('AlfrescoContentService', () => {
@ -28,6 +29,7 @@ describe('AlfrescoContentService', () => {
beforeEach(() => {
injector = ReflectiveInjector.resolveAndCreate([
HTTP_PROVIDERS,
AlfrescoContentService,
AlfrescoAuthenticationService,
AlfrescoSettingsService

View File

@ -156,8 +156,8 @@ class DocumentListDemo implements OnInit {
alfrescoSettingsService.host = this.host;
if (localStorage.getItem('token')) {
this.token = localStorage.getItem('token');
if (this.authService.getToken()) {
this.token = this.authService.getToken();
}
translation.addTranslationFolder();

View File

@ -27,19 +27,27 @@ import {
AlfrescoContentService
} from 'ng2-alfresco-core';
import { FileNode } from '../assets/document-library.model.mock';
import { ReflectiveInjector } from '@angular/core';
import { DocumentListService } from './document-list.service';
import { HTTP_PROVIDERS } from '@angular/http';
describe('DocumentListService', () => {
let injector;
let service: DocumentListService;
let settingsService: AlfrescoSettingsService;
let authService: AlfrescoAuthenticationService;
let contentService: AlfrescoContentService;
beforeEach(() => {
injector = ReflectiveInjector.resolveAndCreate([
HTTP_PROVIDERS,
AlfrescoAuthenticationService,
AlfrescoSettingsService
]);
settingsService = new AlfrescoSettingsService();
authService = new AlfrescoAuthenticationService(settingsService);
settingsService = injector.get(AlfrescoSettingsService);
authService = injector.get(AlfrescoAuthenticationService);
contentService = new AlfrescoContentService(settingsService, authService);
service = new DocumentListService(settingsService, authService, contentService);
});

View File

@ -80,7 +80,7 @@ Also make sure you include these dependencies in your .html page:
```html
<alfresco-login></alfresco-login>
<alfresco-login providers=['ECM','BPM']></alfresco-login>
```
Example of an App that use Alfresco login component :
@ -100,7 +100,12 @@ import {
@Component({
selector: 'my-app',
template: '<alfresco-login (onSuccess)="mySuccessMethod($event)" (onError)="myErrorMethod($event)"></alfresco-login>',
template: '
<alfresco-login
providers=['ECM']
(onSuccess)="mySuccessMethod($event)"
(onError)="myErrorMethod($event)">
</alfresco-login>',
directives: [AlfrescoLoginComponent]
})
export class AppComponent {
@ -133,8 +138,14 @@ bootstrap(AppComponent, [
#### Options
**method**: {string} optional) default POST. The method attribute specifies how to send form-data
The form-data can be sent as URL variables (with method="get") or as HTTP post transaction (with method="post").<br />
**providers**: { string[] } optional) default ECM.
Using the providers attribute, you can specify in which system
(ECM or BPM) you want to be logged in.
By selecting one of the options only the relative components will be
accesible. For instance if you activate the ECM login then only the
ECM component will be visible,same behaviour for BPM selection.
You can also specify ECM and BPM, in this case both system components
are accessible.<br />
## Build from sources
Alternatively you can build component from sources with the following commands:

View File

@ -30,9 +30,25 @@ import {
selector: 'my-app',
template: `<label for="token"><b>Insert the ip of your Alfresco instance:</b></label><br>
<input id="token" type="text" size="48" (change)="updateHost()" [(ngModel)]="host"><br><br>
<div style="border-radius: 8px; position: absolute; background-color: papayawhip; color: cadetblue; left: 10px; top: 120px; z-index: 1;">
<p style="width:120px;margin: 20px;">
<label for="switch1" class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input type="checkbox" id="switch1" class="mdl-switch__input" checked (click)="toggleECM(ecm.checked)" #ecm>
<span class="mdl-switch__label">ECM</span>
</label>
</p>
<p style="width:120px;margin: 20px;">
<label for="switch2" class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input type="checkbox" id="switch2" class="mdl-switch__input" (click)="toggleBPM(bpm.checked)" #bpm>
<span class="mdl-switch__label">BPM</span>
</label>
</p>
</div>
{{ status }}
<hr>
<alfresco-login (onSuccess)="mySuccessMethod($event)" (onError)="myErrorMethod($event)"></alfresco-login>`,
<alfresco-login [providers]="providers" (onSuccess)="mySuccessMethod($event)"
(onError)="myErrorMethod($event)"></alfresco-login>`,
directives: [AlfrescoLoginComponent]
})
export class AppComponent {
@ -43,6 +59,8 @@ export class AppComponent {
public status: string = '';
public providers: string [] = ['ECM'];
constructor(public auth: AlfrescoAuthenticationService,
private alfrescoSettingsService: AlfrescoSettingsService) {
alfrescoSettingsService.host = this.host;
@ -61,6 +79,22 @@ export class AppComponent {
console.log('Error Login EventEmitt called with: ' + $event.value);
this.status = $event.value;
}
toggleECM(checked) {
if (checked) {
this.providers[0] = 'ECM';
} else {
this.providers[0] = '';
}
}
toggleBPM(checked) {
if (checked) {
this.providers[1] = 'BPM';
} else {
this.providers[1] = '';
}
}
}
bootstrap(AppComponent, [

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, Output, EventEmitter } from '@angular/core';
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { FORM_DIRECTIVES, ControlGroup, FormBuilder, Validators } from '@angular/common';
import {
AlfrescoTranslationService,
@ -41,6 +41,9 @@ export class AlfrescoLoginComponent {
isPasswordShow: boolean = false;
@Input()
providers: string [] ;
@Output()
onSuccess = new EventEmitter();
@Output()
@ -102,7 +105,7 @@ export class AlfrescoLoginComponent {
if (event) {
event.preventDefault();
}
this.auth.login(value.username, value.password)
this.auth.login(value.username, value.password, this.providers)
.subscribe(
(token: any) => {
this.success = true;

View File

@ -67,8 +67,8 @@ class SearchDemo implements OnInit {
translation: AlfrescoTranslationService) {
alfrescoSettingsService.host = this.host;
if (localStorage.getItem('token')) {
this.token = localStorage.getItem('token');
if (this.authService.getToken()) {
this.token = this.authService.getToken();
}
translation.addTranslationFolder();

View File

@ -83,8 +83,8 @@ export class MyDemoApp implements OnInit {
constructor(private authService: AlfrescoAuthenticationService, private alfrescoSettingsService: AlfrescoSettingsService) {
alfrescoSettingsService.host = this.host;
if (localStorage.getItem('token')) {
this.token = localStorage.getItem('token');
if (this.authService.getToken()) {
this.token = this.authService.getToken();
}
}

View File

@ -18,15 +18,16 @@
import { Observable } from 'rxjs/Observable';
import { FileModel } from '../models/file.model';
import { UploadService } from '../services/upload.service';
import { AlfrescoSettingsService } from 'ng2-alfresco-core';
import { AlfrescoSettingsService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
export class UploadServiceMock extends UploadService {
filesUpload$: Observable<any>;
totalCompleted$: Observable<number>;
constructor(settings: AlfrescoSettingsService) {
super(settings);
constructor(settings: AlfrescoSettingsService,
authService: AlfrescoAuthenticationService) {
super(settings, authService);
}
public setOptions(options: any): void {

View File

@ -19,11 +19,12 @@ import { describe, expect, it, inject, beforeEach, beforeEachProviders } from '@
import { TestComponentBuilder } from '@angular/compiler/testing';
import { FileUploadingDialogComponent } from './file-uploading-dialog.component';
import { FileModel } from '../models/file.model';
import { AlfrescoTranslationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService, AlfrescoSettingsService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { TranslationMock } from '../assets/translation.service.mock';
import { UploadServiceMock } from '../assets/upload.service.mock';
import { UploadService } from '../services/upload.service';
import { Observable } from 'rxjs/Observable';
import { HTTP_PROVIDERS } from '@angular/http';
describe('FileUploadDialog', () => {
@ -32,7 +33,9 @@ describe('FileUploadDialog', () => {
beforeEachProviders(() => {
return [
HTTP_PROVIDERS,
{ provide: AlfrescoSettingsService, useClass: AlfrescoSettingsService },
{ provide: AlfrescoAuthenticationService, useClass: AlfrescoAuthenticationService },
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
{ provide: UploadService, useClass: UploadServiceMock }
];

View File

@ -18,12 +18,13 @@
import { describe, expect, it, inject, beforeEach, beforeEachProviders } from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { UploadButtonComponent } from './upload-button.component';
import { AlfrescoTranslationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService, AlfrescoSettingsService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { TranslationMock } from '../assets/translation.service.mock';
import { UploadServiceMock } from '../assets/upload.service.mock';
import { UploadService } from '../services/upload.service';
import { AlfrescoApiMock } from '../assets/AlfrescoApi.mock';
import { AlfrescoSettingsServiceMock } from '../assets/AlfrescoSettingsService.service.mock';
import { HTTP_PROVIDERS } from '@angular/http';
declare var AlfrescoApi: any;
@ -38,7 +39,9 @@ describe('AlfrescoUploadButton', () => {
beforeEachProviders(() => {
return [
HTTP_PROVIDERS,
{ provide: AlfrescoSettingsService, useClass: AlfrescoSettingsServiceMock },
{ provide: AlfrescoAuthenticationService, useClass: AlfrescoAuthenticationService },
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
{ provide: UploadService, useClass: UploadServiceMock }
];

View File

@ -18,12 +18,13 @@
import { describe, expect, it, inject, beforeEach, beforeEachProviders } from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { UploadDragAreaComponent } from './upload-drag-area.component';
import { AlfrescoTranslationService, AlfrescoSettingsService } from 'ng2-alfresco-core';
import { AlfrescoTranslationService, AlfrescoSettingsService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { AlfrescoSettingsServiceMock } from '../assets/AlfrescoSettingsService.service.mock';
import { TranslationMock } from '../assets/translation.service.mock';
import { UploadServiceMock } from '../assets/upload.service.mock';
import { UploadService } from '../services/upload.service';
import { AlfrescoApiMock } from '../assets/AlfrescoApi.mock';
import { HTTP_PROVIDERS } from '@angular/http';
declare var AlfrescoApi: any;
@ -37,7 +38,9 @@ describe('AlfrescoUploadDragArea', () => {
beforeEachProviders(() => {
return [
HTTP_PROVIDERS,
{ provide: AlfrescoSettingsService, useClass: AlfrescoSettingsServiceMock },
{ provide: AlfrescoAuthenticationService, useClass: AlfrescoAuthenticationService },
{ provide: AlfrescoTranslationService, useClass: TranslationMock },
{ provide: UploadService, useClass: UploadServiceMock }
];

View File

@ -18,9 +18,10 @@
import { it, describe, inject, beforeEach, beforeEachProviders } from '@angular/core/testing';
import { UploadService } from './upload.service';
import { FileModel } from './../models/file.model';
import { AlfrescoSettingsService } from 'ng2-alfresco-core';
import { AlfrescoSettingsService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { AlfrescoSettingsServiceMock } from '../assets/AlfrescoSettingsService.service.mock';
import { AlfrescoApiMock } from '../assets/AlfrescoApi.mock';
import { HTTP_PROVIDERS } from '@angular/http';
declare var AlfrescoApi: any;
declare let jasmine: any;
@ -30,8 +31,9 @@ let errorFn = jasmine.createSpy('error');
class MockUploadService extends UploadService {
constructor(settings: AlfrescoSettingsService) {
super(settings);
constructor(settings: AlfrescoSettingsService,
authService: AlfrescoAuthenticationService) {
super(settings, authService);
}
createXMLHttpRequestInstance() {
@ -65,7 +67,9 @@ describe('AlfrescoUploadService', () => {
beforeEachProviders(() => {
return [
HTTP_PROVIDERS,
{ provide: AlfrescoSettingsService, useClass: AlfrescoSettingsServiceMock },
{ provide: AlfrescoAuthenticationService, useClass: AlfrescoAuthenticationService },
{ provide: UploadService, useClass: MockUploadService }
];
});

View File

@ -20,7 +20,7 @@ import { EventEmitter, Injectable } from '@angular/core';
import { Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { AlfrescoSettingsService } from 'ng2-alfresco-core';
import { AlfrescoSettingsService, AlfrescoAuthenticationService } from 'ng2-alfresco-core';
import { FileModel } from '../models/file.model';
declare let AlfrescoApi: any;
@ -50,7 +50,8 @@ export class UploadService {
public totalCompleted: number = 0;
constructor(private settings: AlfrescoSettingsService) {
constructor(private settings: AlfrescoSettingsService,
private authService: AlfrescoAuthenticationService) {
console.log('UploadService constructor');
this.filesUpload$ = new Observable<FileModel[]>(observer => this._filesUploadObserver = observer).share();
this.totalCompleted$ = new Observable<number>(observer => this._totalCompletedObserver = observer).share();
@ -92,20 +93,12 @@ export class UploadService {
return this._formFields;
}
/**
* Get the token from the local storage
* @returns {any}
*/
private getAlfrescoTicket(): string {
return localStorage.getItem('token');
}
/**
* Get the alfresco client
* @returns {AlfrescoApi.ApiClient}
*/
private getAlfrescoClient() {
return AlfrescoApi.getClientWithTicket(this.settings.getApiBaseUrl(), this.getAlfrescoTicket());
return AlfrescoApi.getClientWithTicket(this.settings.getApiBaseUrl(), this.authService.getToken());
}
/**