[ADF-2795] SSO implicitflow (#3332)

* Enable OAUTH2

* Create SSO services

* SSO improvements

* Rollback sso login change

* Add SSO configuration from Setting component

* Refactoring

* Remove login ECM/BPM toggle and move use the userpreference instead of store

* fix host setting unit test

* Fix unit test missing instance

* use the Js api oauth

* add logout component and clean sso not used class

* fix dependencies cicle

* add translation settings

* fix style setting page

* clean

* JS APi should receive the oauth config from the userPreference and not from the config file

* change login if SSO is present

* missing spaces

* add sso test in login component

* add logout directive new properties test

* Improve host setting and remove library reference

* fix login test

* Remove unused code

* Fix authentication unit test

* fix authguard unit test

* fix csrf check login component

* fix unit test core and demo shell

* remove
This commit is contained in:
Maurizio Vitale
2018-06-07 23:19:58 +01:00
committed by Eugenio Romano
parent 3a6c12e624
commit f8e92b2fb0
57 changed files with 1295 additions and 681 deletions

View File

@@ -6,6 +6,16 @@
"PROPERTIES": "Properties",
"VERSIONS": "Versions"
},
"HOME": {
"TITLE": "Angular components for Alfresco",
"DOCUMENTATION": "Documentation"
},
"LOGOUT": {
"TITLE": "Logout Page",
"SUB_TITLE": "You are now logged out",
"LOGIN": "Login",
"HOME": "Home"
},
"ADF_VERSION_MANAGER": {
"ALLOW_DELETE": "Allow delete",
"SHOW_COMMENTS" : "Show comments on versions",

View File

@@ -2,7 +2,18 @@
"$schema": "../../lib/core/app-config/schema.json",
"ecmHost": "http://{hostname}:{port}",
"bpmHost": "http://{hostname}:{port}",
"providers": "OAUTH",
"contextRootBpm": "activiti-app",
"oauth2": {
"host": "YOUR_AUTH_SERVER",
"clientId": "activiti",
"scope": "openid",
"secret": "",
"implicitFlow": true,
"silentLogin": true,
"redirectUri": "/",
"redirectUriLogout": "/logout"
},
"application": {
"name": "Alfresco ADF Application",
"copyright": "© 2016 - 2018 Alfresco Software, Inc. All Rights Reserved."

View File

@@ -16,7 +16,7 @@
*/
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { AlfrescoApiService, SettingsService, PageTitleService, StorageService } from '@alfresco/adf-core';
import { AlfrescoApiService, PageTitleService } from '@alfresco/adf-core';
import { Router } from '@angular/router';
@Component({
@@ -27,15 +27,12 @@ import { Router } from '@angular/router';
})
export class AppComponent implements OnInit {
constructor(private settingsService: SettingsService,
private storage: StorageService,
private pageTitleService: PageTitleService,
constructor(private pageTitleService: PageTitleService,
private alfrescoApiService: AlfrescoApiService,
private router: Router) {
}
ngOnInit() {
this.setProvider();
this.pageTitleService.setTitle('title');
@@ -46,10 +43,4 @@ export class AppComponent implements OnInit {
}
});
}
private setProvider() {
if (this.storage.hasItem(`providers`)) {
this.settingsService.setProviders(this.storage.getItem(`providers`));
}
}
}

View File

@@ -11,6 +11,7 @@ import { AppComponent } from './app.component';
import { AdfModule } from './adf.module';
import { MaterialModule } from './material.module';
import { LoginComponent } from './components/login/login.component';
import { LogoutComponent } from './components/logout/logout.component';
import { SettingsComponent } from './components/settings/settings.component';
import { AppLayoutComponent } from './components/app-layout/app-layout.component';
import { HomeComponent } from './components/home/home.component';
@@ -71,6 +72,7 @@ import { NotificationsComponent } from './components/notifications/notifications
declarations: [
AppComponent,
LoginComponent,
LogoutComponent,
SettingsComponent,
AppLayoutComponent,
HomeComponent,

View File

@@ -17,11 +17,12 @@
import { ModuleWithProviders } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard, AuthGuardBpm, AuthGuardEcm, ErrorContentComponent } from '@alfresco/adf-core';
import { AuthGuard, AuthGuardEcm, ErrorContentComponent, AuthGuardBpm } from '@alfresco/adf-core';
import { AppLayoutComponent } from './components/app-layout/app-layout.component';
import { LoginComponent } from './components/login/login.component';
import { SettingsComponent } from './components/settings/settings.component';
import { HomeComponent } from './components/home/home.component';
import { LogoutComponent } from './components/logout/logout.component';
import { AboutComponent } from './components/about/about.component';
import { ProcessServiceComponent } from './components/process-service/process-service.component';
import { ShowDiagramComponent } from './components/process-service/show-diagram.component';
@@ -52,8 +53,9 @@ import { NotificationsComponent } from './components/notifications/notifications
export const appRoutes: Routes = [
{ path: 'login', component: LoginComponent },
{ path: 'logout', component: LogoutComponent },
{ path: 'settings', component: SettingsComponent },
{ path: 'files/:nodeId/view', component: FileViewComponent, canActivate: [AuthGuardEcm], outlet: 'overlay' },
{ path: 'files/:nodeId/view', component: FileViewComponent, canActivate: [ AuthGuardEcm ], outlet: 'overlay' },
{ path: 'preview/blob', component: BlobPreviewComponent, outlet: 'overlay', pathMatch: 'full' },
{ path: 'preview/s/:id', component: SharedLinkViewComponent },
{
@@ -226,4 +228,4 @@ export const appRoutes: Routes = [
}
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, { initialNavigation: true });

View File

@@ -37,7 +37,7 @@
<mat-icon matListIcon class="sidenav-menu-icon">{{link.icon}}</mat-icon>
<div class="sidenav-menu-label" *ngIf="!isMenuMinimized()">{{link.title | translate }}</div>
</a>
<a mat-list-item adf-logout class="adf-sidenav-link">
<a mat-list-item adf-logout [enabelRedirect]="enabelRedirect" redirectUri="/logout" class="adf-sidenav-link">
<mat-icon matListIcon class="sidenav-menu-icon">exit_to_app</mat-icon>
<div class="sidenav-menu-label" *ngIf="!isMenuMinimized()">Logout</div>
</a>

View File

@@ -16,7 +16,7 @@
*/
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core';
import { UserPreferencesService, AppConfigService, AlfrescoApiService } from '@alfresco/adf-core';
@Component({
templateUrl: 'app-layout.component.html',
@@ -54,18 +54,23 @@ export class AppLayoutComponent implements OnInit {
expandedSidenav = false;
enabelRedirect = true;
ngOnInit() {
const expand = this.config.get<boolean>('sideNav.expandedSidenav');
const preserveState = this.config.get('sideNav.preserveState');
if (preserveState && expand) {
if (preserveState && expand) {
this.expandedSidenav = (this.userpreference.get('expandedSidenav', expand.toString()) === 'true');
} else if (expand) {
this.expandedSidenav = expand;
}
}
constructor( private userpreference: UserPreferencesService, private config: AppConfigService) {
constructor(private userpreference: UserPreferencesService, private config: AppConfigService, private alfrescoApiService: AlfrescoApiService) {
if (this.alfrescoApiService.getInstance().isOauthConfiguration()) {
this.enabelRedirect = false;
}
}
setState(state) {

View File

@@ -25,7 +25,7 @@ import { MatDialog } from '@angular/material';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { MinimalNodeEntity, NodePaging, Pagination, MinimalNodeEntryEntity, SiteEntry } from 'alfresco-js-api';
import {
AuthenticationService, AppConfigService, ContentService, TranslationService,
AuthenticationService, ContentService, TranslationService,
FileUploadEvent, FolderCreatedEvent, LogService, NotificationService,
UploadService, DataColumn, DataRow, UserPreferencesService,
PaginationComponent, FormValues, DisplayMode, UserPreferenceValues, InfinitePaginationComponent
@@ -56,7 +56,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
displayMode = DisplayMode.List;
includeFields = ['isFavorite', 'isLocked', 'aspectNames'];
baseShareUrl = this.appConfig.get<string>('ecmHost') + '/preview/s/';
baseShareUrl = this.preference.ecmHost + '/preview/s/';
toolbarColor = 'default';
@@ -191,7 +191,6 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
private router: Router,
private logService: LogService,
private preference: UserPreferencesService,
private appConfig: AppConfigService,
private preview: PreviewService,
@Optional() private route: ActivatedRoute,
public authenticationService: AuthenticationService) {

View File

@@ -2,10 +2,10 @@
<div class="adf-home-section ad">
<div class="adf-home-headline">
<h1 class="mat-h1">ADF</h1>
<h2> Angular components for Alfresco</h2>
<h2>{{ 'APP.HOME.TITLE' | translate}}</h2>
</div>
<div class="adf-home-start">
<a mat-raised-button class="adf-home-docs-button adf-primary-color" href="https://github.com/Alfresco/alfresco-ng2-components/tree/master/docs">DOCS</a>
<a mat-raised-button class="adf-home-docs-button adf-primary-color" href="https://github.com/Alfresco/alfresco-ng2-components/tree/master/docs">{{ 'APP.HOME.DOCUMENTATION' | translate}}</a>
</div>
</div>
</header>

View File

@@ -1,24 +1,6 @@
<!--BPM, ECN AND CSRF TOGGLE-->
<div class="settings">
<p class="toggle">
<mat-slide-toggle
id="switch1"
[color]="'primary'"
(change)="toggleECM()"
[checked]="isECM">
{{ 'LOGIN.CONTENT_SERVICES'| translate }}
</mat-slide-toggle>
</p>
<p class="toggle">
<mat-slide-toggle
id="switch2"
[color]="'primary'"
(change)="toggleBPM()"
[checked]="isBPM">
{{ 'LOGIN.PROCESS_SERVICES'| translate }}
</mat-slide-toggle>
</p>
<p class="toggle">
<mat-slide-toggle
id="switch3"
@@ -57,24 +39,6 @@
(success)="onLogin($event)"
(error)="onError($event)">
<div class="mobile-settings">
<p>
<mat-slide-toggle
id="switch1-mobile"
[color]="'primary'"
(change)="toggleECM()"
[checked]="isECM">
{{ 'LOGIN.CONTENT_SERVICES'| translate }}
</mat-slide-toggle>
</p>
<p>
<mat-slide-toggle
id="switch2-mobile"
[color]="'primary'"
(change)="toggleBPM()"
[checked]="isBPM">
{{ 'LOGIN.PROCESS_SERVICES'| translate }}
</mat-slide-toggle>
</p>
<p>
<mat-slide-toggle
id="switch3-mobile"

View File

@@ -18,7 +18,7 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { LogService, StorageService } from '@alfresco/adf-core';
import { LogService, UserPreferencesService } from '@alfresco/adf-core';
@Component({
selector: 'app-login',
@@ -34,13 +34,11 @@ export class LoginComponent implements OnInit {
customValidation: any;
disableCsrf = false;
isECM = true;
isBPM = false;
showFooter = true;
customMinLength = 2;
constructor(private router: Router,
private storage: StorageService,
private userPreference: UserPreferencesService,
private logService: LogService) {
this.customValidation = {
username: ['', Validators.compose([Validators.required, Validators.minLength(this.customMinLength)])],
@@ -53,24 +51,11 @@ export class LoginComponent implements OnInit {
this.alfrescologin.addCustomValidationError('username', 'minlength', 'LOGIN.MESSAGES.USERNAME-MIN', {minLength: this.customMinLength});
this.alfrescologin.addCustomValidationError('password', 'required', 'LOGIN.MESSAGES.PASSWORD-REQUIRED');
if (this.storage.hasItem('providers')) {
this.providers = this.storage.getItem('providers');
}
this.initProviders();
}
initProviders() {
if (this.providers === 'BPM') {
this.isECM = false;
this.isBPM = true;
} else if (this.providers === 'ECM') {
this.isECM = true;
this.isBPM = false;
} else if (this.providers === 'ALL') {
this.isECM = true;
this.isBPM = true;
}
this.providers = this.userPreference.providers;
}
onLogin($event) {
@@ -81,16 +66,6 @@ export class LoginComponent implements OnInit {
this.logService.error($event);
}
toggleECM() {
this.isECM = !this.isECM;
this.storage.setItem('providers', this.updateProvider());
}
toggleBPM() {
this.isBPM = !this.isBPM;
this.storage.setItem('providers', this.updateProvider());
}
toggleCSRF() {
this.disableCsrf = !this.disableCsrf;
}
@@ -99,26 +74,6 @@ export class LoginComponent implements OnInit {
this.showFooter = !this.showFooter;
}
updateProvider() {
if (this.isBPM && this.isECM) {
this.providers = 'ALL';
return this.providers;
}
if (this.isECM) {
this.providers = 'ECM';
return this.providers;
}
if (this.isBPM) {
this.providers = 'BPM';
return this.providers;
}
this.providers = '';
return this.providers;
}
checkForm(event: any) {
const values = event.values;
this.logService.log(values);

View File

@@ -0,0 +1,17 @@
<header class="adf-logout-background">
<div class="adf-logout-section">
<div class="adf-logout-headline">
<h1>{{ 'APP.LOGOUT.TITLE' | translate}}</h1>
<h2>{{ 'APP.LOGOUT.SUB_TITLE' | translate}}</h2>
</div>
<div class="adf-logout-login">
<a mat-raised-button class="adf-logout-docs-button adf-primary-color"
href="/login">{{ 'APP.LOGOUT.LOGIN' | translate}}</a>
</div>
<div class="adf-logout-home">
<a mat-raised-button class="adf-logout-docs-button adf-primary-color"
href="/">{{ 'APP.LOGOUT.HOME' | translate}}</a>
</div>
</div>
</header>

View File

@@ -0,0 +1,39 @@
:host {
display: flex;
justify-content: center;
align-items: center;
}
.adf-logout-header-background {
overflow: hidden;
}
.adf-logout-section {
text-align: center;
padding-top: 60px;
}
.adf-logout-headline {
h1 {
font-size: 56px;
font-weight: 300;
line-height: 56px;
margin: 15px 5px;
}
h2 {
font-size: 18px;
font-weight: 300;
line-height: 28px;
margin: 15px 0 25px 0;
}
}
.adf-logout-docs-button {
margin: 30px;
}
.adf-logout-login {
float: left;
}

View File

@@ -0,0 +1,25 @@
/*!
* @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 { Component } from '@angular/core';
@Component({
selector: 'app-logout',
templateUrl: './logout.component.html',
styleUrls: ['./logout.component.scss']
})
export class LogoutComponent {}

View File

@@ -1 +1 @@
<adf-host-settings (error)="onError($event)"></adf-host-settings>
<adf-host-settings (cancel)="onCancel($event)" (success)="onSuccess($event)" (error)="onError($event)"></adf-host-settings>

View File

@@ -16,7 +16,8 @@
*/
import { Component } from '@angular/core';
import { LogService } from '@alfresco/adf-core';
import { LogService, AuthenticationService, AlfrescoApiService } from '@alfresco/adf-core';
import { Router } from '@angular/router';
@Component({
selector: 'app-settings',
@@ -24,10 +25,23 @@ import { LogService } from '@alfresco/adf-core';
})
export class SettingsComponent {
constructor(public logService: LogService) {
constructor(private router: Router,
private authService: AuthenticationService,
private alfrescoApiService: AlfrescoApiService,
public logService: LogService) {
}
onError(error: string) {
this.logService.log(error);
}
onCancel() {
this.router.navigate(['/']);
}
onSuccess() {
this.authService.removeTicket();
this.alfrescoApiService.reset();
this.router.navigate(['/']);
}
}