mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-06-02 17:35:08 +00:00
OIDC first try
This commit is contained in:
parent
bc1e671430
commit
9d976105e3
@ -16,6 +16,7 @@
|
|||||||
"threads": 1
|
"threads": 1
|
||||||
},
|
},
|
||||||
"oauth2": {
|
"oauth2": {
|
||||||
|
"handler": "oidc",
|
||||||
"host": "{protocol}//{hostname}{:port}/auth/realms/alfresco",
|
"host": "{protocol}//{hostname}{:port}/auth/realms/alfresco",
|
||||||
"clientId": "alfresco",
|
"clientId": "alfresco",
|
||||||
"scope": "openid",
|
"scope": "openid",
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
AuthenticationService,
|
// AuthenticationService,
|
||||||
AlfrescoApiService,
|
// AlfrescoApiService,
|
||||||
PageTitleService
|
PageTitleService
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { Router } from '@angular/router';
|
// import { Router } from '@angular/router';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
// import { MatDialog } from '@angular/material/dialog';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@ -33,30 +33,31 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
|
|
||||||
constructor(private pageTitleService: PageTitleService,
|
constructor(private pageTitleService: PageTitleService,
|
||||||
private alfrescoApiService: AlfrescoApiService,
|
// private alfrescoApiService: AlfrescoApiService,
|
||||||
private authenticationService: AuthenticationService,
|
// private authenticationService: AuthenticationService,
|
||||||
private router: Router,
|
// private router: Router,
|
||||||
private dialogRef: MatDialog) {
|
// private dialogRef: MatDialog
|
||||||
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.pageTitleService.setTitle('title');
|
this.pageTitleService.setTitle('title');
|
||||||
|
|
||||||
this.alfrescoApiService.getInstance().on('error', (error) => {
|
// this.alfrescoApiService.getInstance().on('error', (error) => {
|
||||||
if (error.status === 401) {
|
// if (error.status === 401) {
|
||||||
if (!this.authenticationService.isLoggedIn()) {
|
// if (!this.authenticationService.isLoggedIn()) {
|
||||||
this.dialogRef.closeAll();
|
// this.dialogRef.closeAll();
|
||||||
this.router.navigate(['/login']);
|
// this.router.navigate(['/login']);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (error.status === 507) {
|
// if (error.status === 507) {
|
||||||
if (!this.authenticationService.isLoggedIn()) {
|
// if (!this.authenticationService.isLoggedIn()) {
|
||||||
this.dialogRef.closeAll();
|
// this.dialogRef.closeAll();
|
||||||
this.router.navigate(['error/507']);
|
// this.router.navigate(['error/507']);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@ import {
|
|||||||
TRANSLATION_PROVIDER,
|
TRANSLATION_PROVIDER,
|
||||||
DebugAppConfigService,
|
DebugAppConfigService,
|
||||||
CoreModule,
|
CoreModule,
|
||||||
CoreAutomationService
|
CoreAutomationService,
|
||||||
|
AppConfigModule
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { ExtensionsModule } from '@alfresco/adf-extensions';
|
import { ExtensionsModule } from '@alfresco/adf-extensions';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
@ -115,6 +116,7 @@ import { setupAppNotifications } from './services/app-notifications-factory';
|
|||||||
import { AppNotificationsService } from './services/app-notifications.service';
|
import { AppNotificationsService } from './services/app-notifications.service';
|
||||||
import { SearchFilterChipsComponent } from './components/search/search-filter-chips.component';
|
import { SearchFilterChipsComponent } from './components/search/search-filter-chips.component';
|
||||||
import { AlfrescoApiModule } from '@alfresco/adf-core/alfresco-api';
|
import { AlfrescoApiModule } from '@alfresco/adf-core/alfresco-api';
|
||||||
|
import { OIDCAuthModule } from '@alfresco/adf-core/authentication';
|
||||||
|
|
||||||
registerLocaleData(localeFr);
|
registerLocaleData(localeFr);
|
||||||
registerLocaleData(localeDe);
|
registerLocaleData(localeDe);
|
||||||
@ -138,13 +140,15 @@ registerLocaleData(localeSv);
|
|||||||
BrowserModule,
|
BrowserModule,
|
||||||
environment.e2e ? NoopAnimationsModule : BrowserAnimationsModule,
|
environment.e2e ? NoopAnimationsModule : BrowserAnimationsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
RouterModule.forRoot(appRoutes, { useHash: true, relativeLinkResolution: 'legacy' }),
|
// initialNavigation: false needs because of the OIDC package!!!
|
||||||
|
// https://manfredsteyer.github.io/angular-oauth2-oidc/docs/additional-documentation/routing-with-the-hashstrategy.html
|
||||||
|
RouterModule.forRoot(appRoutes, { useHash: true, relativeLinkResolution: 'legacy', initialNavigation: false }),
|
||||||
FormsModule,
|
FormsModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
MaterialModule,
|
MaterialModule,
|
||||||
FlexLayoutModule,
|
FlexLayoutModule,
|
||||||
TranslateModule.forRoot(),
|
TranslateModule.forRoot(),
|
||||||
CoreModule.forRoot(),
|
CoreModule.forRoot({ legacyAlfrescoApiService: false }),
|
||||||
ContentModule.forRoot(),
|
ContentModule.forRoot(),
|
||||||
InsightsModule.forRoot(),
|
InsightsModule.forRoot(),
|
||||||
ProcessModule.forRoot(),
|
ProcessModule.forRoot(),
|
||||||
@ -154,6 +158,8 @@ registerLocaleData(localeSv);
|
|||||||
ChartsModule,
|
ChartsModule,
|
||||||
AppCloudSharedModule,
|
AppCloudSharedModule,
|
||||||
AlfrescoApiModule,
|
AlfrescoApiModule,
|
||||||
|
AppConfigModule.forRoot(),
|
||||||
|
OIDCAuthModule,
|
||||||
MonacoEditorModule.forRoot()
|
MonacoEditorModule.forRoot()
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -56,6 +56,7 @@ import { ProcessCloudLayoutComponent } from './components/cloud/process-cloud-la
|
|||||||
import { ServiceTaskListCloudDemoComponent } from './components/cloud/service-task-list-cloud-demo.component';
|
import { ServiceTaskListCloudDemoComponent } from './components/cloud/service-task-list-cloud-demo.component';
|
||||||
import { AspectListSampleComponent } from './components/aspect-list-sample/aspect-list-sample.component';
|
import { AspectListSampleComponent } from './components/aspect-list-sample/aspect-list-sample.component';
|
||||||
import { SearchFilterChipsComponent } from './components/search/search-filter-chips.component';
|
import { SearchFilterChipsComponent } from './components/search/search-filter-chips.component';
|
||||||
|
import { OIDCAuthGuard } from '@alfresco/adf-core/authentication';
|
||||||
|
|
||||||
export const appRoutes: Routes = [
|
export const appRoutes: Routes = [
|
||||||
{ path: 'login', loadChildren: () => import('./components/login/login.module').then(m => m.AppLoginModule) },
|
{ path: 'login', loadChildren: () => import('./components/login/login.module').then(m => m.AppLoginModule) },
|
||||||
@ -106,7 +107,7 @@ export const appRoutes: Routes = [
|
|||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: AppLayoutComponent,
|
component: AppLayoutComponent,
|
||||||
canActivate: [AuthGuard],
|
canActivate: [AuthGuard, OIDCAuthGuard],
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
|
@ -16,7 +16,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, ViewEncapsulation, OnInit, OnDestroy } from '@angular/core';
|
import { Component, ViewEncapsulation, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { UserPreferencesService, AppConfigService, AlfrescoApiService, UserPreferenceValues } from '@alfresco/adf-core';
|
import {
|
||||||
|
UserPreferencesService,
|
||||||
|
AppConfigService,
|
||||||
|
// AlfrescoApiService,
|
||||||
|
UserPreferenceValues
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
import { HeaderDataService } from '../header-data/header-data.service';
|
import { HeaderDataService } from '../header-data/header-data.service';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
@ -169,11 +174,11 @@ export class AppLayoutComponent implements OnInit, OnDestroy {
|
|||||||
constructor(
|
constructor(
|
||||||
private userPreferences: UserPreferencesService,
|
private userPreferences: UserPreferencesService,
|
||||||
private config: AppConfigService,
|
private config: AppConfigService,
|
||||||
private alfrescoApiService: AlfrescoApiService,
|
// private alfrescoApiService: AlfrescoApiService,
|
||||||
private headerService: HeaderDataService) {
|
private headerService: HeaderDataService) {
|
||||||
if (this.alfrescoApiService.getInstance().isOauthConfiguration()) {
|
// if (this.alfrescoApiService.getInstance().isOauthConfiguration()) {
|
||||||
this.enableRedirect = false;
|
// this.enableRedirect = false;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(state) {
|
setState(state) {
|
||||||
|
@ -19,10 +19,12 @@
|
|||||||
|
|
||||||
import { HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
import { HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||||
import { AlfrescoApiV2Service } from './services/alfresco-api-v2.service';
|
import { AlfrescoApiV2 } from './services/alfresco-api-v2';
|
||||||
import { AlfrescoApiClientFactory } from './services/alfresco-api-client.factory';
|
import { AlfrescoApiClientFactory } from './services/alfresco-api-client.factory';
|
||||||
import { AlfrescoApiV2LoaderService, createAlfrescoApiV2Service } from './services/alfresco-api-v2-loader.service';
|
import { AlfrescoApiV2LoaderService, createAlfrescoApiV2Service } from './services/alfresco-api-v2-loader.service';
|
||||||
import { AuthBearerInterceptor } from './services/auth-bearer.interceptor';
|
import { AuthBearerInterceptor } from './services/auth-bearer.interceptor';
|
||||||
|
import { LegacyAlfrescoApiServiceFacade } from './services/legacy-alfresco-api-service.facade';
|
||||||
|
import { AlfrescoApiService } from '../services/alfresco-api.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -33,8 +35,9 @@ import { AuthBearerInterceptor } from './services/auth-bearer.interceptor';
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
AlfrescoApiV2Service,
|
AlfrescoApiV2,
|
||||||
AlfrescoApiV2LoaderService,
|
AlfrescoApiV2LoaderService,
|
||||||
|
LegacyAlfrescoApiServiceFacade,
|
||||||
AlfrescoApiClientFactory,
|
AlfrescoApiClientFactory,
|
||||||
{
|
{
|
||||||
provide: APP_INITIALIZER,
|
provide: APP_INITIALIZER,
|
||||||
@ -47,6 +50,11 @@ import { AuthBearerInterceptor } from './services/auth-bearer.interceptor';
|
|||||||
{
|
{
|
||||||
provide: HTTP_INTERCEPTORS, useClass:
|
provide: HTTP_INTERCEPTORS, useClass:
|
||||||
AuthBearerInterceptor, multi: true
|
AuthBearerInterceptor, multi: true
|
||||||
|
},
|
||||||
|
// Reproviding legacy like service for older code
|
||||||
|
{
|
||||||
|
provide: AlfrescoApiService,
|
||||||
|
useExisting: LegacyAlfrescoApiServiceFacade
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -16,5 +16,5 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './alfresco-api.module';
|
export * from './alfresco-api.module';
|
||||||
export * from './services/alfresco-api-v2.service';
|
export * from './services/alfresco-api-v2';
|
||||||
export * from './services/alfresco-api-client.factory';
|
export * from './services/alfresco-api-client.factory';
|
||||||
|
67
lib/core/alfresco-api/js-api/alfresco-api-type.ts
Normal file
67
lib/core/alfresco-api/js-api/alfresco-api-type.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*tslint:disable*/ // => because of ADF file naming problems... Try to remove it, if you don't believe me :P
|
||||||
|
|
||||||
|
import { AlfrescoApiConfig } from '@alfresco/js-api';
|
||||||
|
import { JsApiHttpClient } from './js-api-http-client';
|
||||||
|
|
||||||
|
export interface LegacyTicketApi {
|
||||||
|
getAlfTicket(ticket: string): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracted from existing AlfrescoApi:
|
||||||
|
export interface AlfrescoApiType {
|
||||||
|
config: AlfrescoApiConfig;
|
||||||
|
contentClient: JsApiHttpClient & LegacyTicketApi;
|
||||||
|
contentPrivateClient: JsApiHttpClient & LegacyTicketApi;
|
||||||
|
processClient: JsApiHttpClient;
|
||||||
|
searchClient: JsApiHttpClient;
|
||||||
|
discoveryClient: JsApiHttpClient;
|
||||||
|
gsClient: JsApiHttpClient;
|
||||||
|
authClient: JsApiHttpClient;
|
||||||
|
processAuth?: JsApiHttpClient;
|
||||||
|
|
||||||
|
setConfig(config: AlfrescoApiConfig): void;
|
||||||
|
changeWithCredentialsConfig(withCredentials: boolean) : void;
|
||||||
|
changeCsrfConfig(disableCsrf: boolean): void;
|
||||||
|
changeEcmHost(hostEcm: string): void;
|
||||||
|
changeBpmHost(hostBpm: string): void;
|
||||||
|
login(username: string, password: string): Promise<any>;
|
||||||
|
isCredentialValid(credential: string): boolean;
|
||||||
|
implicitLogin(): Promise<any>;
|
||||||
|
loginTicket(ticketEcm: string, ticketBpm: string): Promise<any>;
|
||||||
|
logout(): Promise<any>;
|
||||||
|
isLoggedIn(): boolean;
|
||||||
|
isBpmLoggedIn(): boolean;
|
||||||
|
isEcmLoggedIn(): boolean;
|
||||||
|
getBpmUsername(): string;
|
||||||
|
getEcmUsername(): string;
|
||||||
|
refreshToken(): Promise<string>;
|
||||||
|
getTicketAuth(): string;
|
||||||
|
setTicket(ticketEcm: string, TicketBpm: string): void;
|
||||||
|
invalidateSession(): void;
|
||||||
|
getTicketBpm(): string;
|
||||||
|
getTicketEcm(): string;
|
||||||
|
getTicket(): string[];
|
||||||
|
isBpmConfiguration(): boolean;
|
||||||
|
isEcmConfiguration(): boolean;
|
||||||
|
isOauthConfiguration(): boolean;
|
||||||
|
isPublicUrl(): boolean;
|
||||||
|
isEcmBpmConfiguration(): boolean;
|
||||||
|
reply(event: string, callback?: any): void;
|
||||||
|
}
|
@ -18,31 +18,45 @@
|
|||||||
/*tslint:disable*/ // => because of ADF file naming problems... Try to remove it, if you don't believe me :P
|
/*tslint:disable*/ // => because of ADF file naming problems... Try to remove it, if you don't believe me :P
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { DiscoveryApi, NodesApi } from '@alfresco/js-api';
|
import { DiscoveryApi, NodesApi, PeopleApi, UserProfileApi } from '@alfresco/js-api';
|
||||||
import { AlfrescoApiV2Service } from './alfresco-api-v2.service';
|
import { AlfrescoApiV2 } from './alfresco-api-v2';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AlfrescoApiClientFactory {
|
export class AlfrescoApiClientFactory {
|
||||||
// Here we should all the APIs from js-api
|
// Here we should have all the APIs from js-api
|
||||||
private discoveryApi: DiscoveryApi = null;
|
private discoveryApi: DiscoveryApi = null;
|
||||||
private nodesApi: NodesApi = null;
|
private nodesApi: NodesApi = null;
|
||||||
|
private peopleApi: PeopleApi = null;
|
||||||
|
private profileApi: UserProfileApi = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private angularAlfrescoApi?: AlfrescoApiV2Service) {
|
private angularAlfrescoApi?: AlfrescoApiV2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
getDiscoveryApi() {
|
getDiscoveryApi(): DiscoveryApi {
|
||||||
// DiscoveryApi needs to rely on a lot thinner interface: JsApiHttpClient; For now: "as any"
|
// DiscoveryApi needs to rely on a lot thinner interface: JsApiHttpClient; For now: "as any"
|
||||||
this.discoveryApi = this.discoveryApi ?? new DiscoveryApi(this.angularAlfrescoApi as any);
|
this.discoveryApi = this.discoveryApi ?? new DiscoveryApi(this.angularAlfrescoApi as any);
|
||||||
return this.discoveryApi;
|
return this.discoveryApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNodesApi () {
|
getNodesApi(): NodesApi {
|
||||||
// NodesApi needs to rely on a lot thinner interface: JsApiHttpClient; For now: "as any"
|
// NodesApi needs to rely on a lot thinner interface: JsApiHttpClient; For now: "as any"
|
||||||
this.nodesApi = this.nodesApi ?? new NodesApi(this.angularAlfrescoApi as any);
|
this.nodesApi = this.nodesApi ?? new NodesApi(this.angularAlfrescoApi as any);
|
||||||
return this.nodesApi;
|
return this.nodesApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPeopleApi(): PeopleApi {
|
||||||
|
// PeopleApi needs to rely on a lot thinner interface: JsApiHttpClient; For now: "as any"
|
||||||
|
this.peopleApi = this.peopleApi ?? new PeopleApi(this.angularAlfrescoApi as any);
|
||||||
|
return this.peopleApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
getProfileApi(): UserProfileApi {
|
||||||
|
// PeopleApi needs to rely on a lot thinner interface: JsApiHttpClient; For now: "as any"
|
||||||
|
this.profileApi = this.profileApi ?? new UserProfileApi(this.angularAlfrescoApi as any);
|
||||||
|
return this.profileApi;
|
||||||
|
}
|
||||||
|
|
||||||
getSearchApi() {
|
getSearchApi() {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,9 @@ import { Injectable } from '@angular/core';
|
|||||||
import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api';
|
import { AlfrescoApi, AlfrescoApiConfig } from '@alfresco/js-api';
|
||||||
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
||||||
import { OauthConfigModel } from '../../models/oauth-config.model';
|
import { OauthConfigModel } from '../../models/oauth-config.model';
|
||||||
import { StorageService } from '../../services/storage.service';
|
import { AlfrescoApiV2 } from './alfresco-api-v2';
|
||||||
import { AlfrescoApiV2Service } from './alfresco-api-v2.service';
|
import { LegacyAlfrescoApiServiceFacade } from './legacy-alfresco-api-service.facade';
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
|
||||||
export function createAlfrescoApiV2Service(angularAlfrescoApiService: AlfrescoApiV2LoaderService) {
|
export function createAlfrescoApiV2Service(angularAlfrescoApiService: AlfrescoApiV2LoaderService) {
|
||||||
return () => angularAlfrescoApiService.load();
|
return () => angularAlfrescoApiService.load();
|
||||||
@ -35,13 +36,12 @@ export class AlfrescoApiV2LoaderService {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected appConfig: AppConfigService,
|
protected appConfig: AppConfigService,
|
||||||
protected storageService: StorageService,
|
private legacyAlfrescoApiServiceFacade: LegacyAlfrescoApiServiceFacade,
|
||||||
private alfrescoApiV2Service?: AlfrescoApiV2Service) {
|
private alfrescoApiV2Service?: AlfrescoApiV2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
load(): Promise<any> {
|
load(): Promise<any> {
|
||||||
return this.appConfig.load().then(() => {
|
return this.appConfig.onLoad.pipe(take(1)).toPromise().then(() => {
|
||||||
this.storageService.prefix = this.appConfig.get<string>(AppConfigValues.STORAGE_PREFIX, '');
|
|
||||||
this.initAngularAlfrescoApi();
|
this.initAngularAlfrescoApi();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -67,5 +67,6 @@ export class AlfrescoApiV2LoaderService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.alfrescoApiV2Service.init(config);
|
this.alfrescoApiV2Service.init(config);
|
||||||
|
this.legacyAlfrescoApiServiceFacade.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
/*!
|
|
||||||
* @license
|
|
||||||
* Copyright 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*tslint:disable*/ // => because of ADF file naming problems... Try to remove it, if you don't believe me :P
|
|
||||||
|
|
||||||
import { AlfrescoApiConfig } from '@alfresco/js-api';
|
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
import { JsApiHttpClient } from '../js-api/js-api-http-client';
|
|
||||||
import { JsApiAngularHttpClient } from './js-api-angular-http-client';
|
|
||||||
import { HttpClient } from '@angular/common/http';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class AlfrescoApiV2Service {
|
|
||||||
public contentPrivateClient: JsApiHttpClient;
|
|
||||||
public contentClient: JsApiHttpClient;
|
|
||||||
public authClient: JsApiHttpClient;
|
|
||||||
public searchClient: JsApiHttpClient;
|
|
||||||
public discoveryClient: JsApiHttpClient;
|
|
||||||
public gsClient: JsApiHttpClient;
|
|
||||||
public processClient: JsApiHttpClient;
|
|
||||||
|
|
||||||
constructor(private httpClient: HttpClient) {}
|
|
||||||
|
|
||||||
init(config: AlfrescoApiConfig) {
|
|
||||||
this.contentPrivateClient = new JsApiAngularHttpClient(
|
|
||||||
config.hostEcm,
|
|
||||||
config.contextRoot,
|
|
||||||
`/api/${config.tenant}/private/alfresco/versions/1`,
|
|
||||||
this.httpClient
|
|
||||||
);
|
|
||||||
|
|
||||||
this.contentClient = new JsApiAngularHttpClient(
|
|
||||||
config.hostEcm,
|
|
||||||
config.contextRoot,
|
|
||||||
`/api/${config.tenant}/public/alfresco/versions/1`,
|
|
||||||
this.httpClient
|
|
||||||
);
|
|
||||||
|
|
||||||
this.authClient = new JsApiAngularHttpClient(
|
|
||||||
config.hostEcm,
|
|
||||||
config.contextRoot,
|
|
||||||
`/api/${config.tenant}/public/authentication/versions/1`,
|
|
||||||
this.httpClient
|
|
||||||
);
|
|
||||||
|
|
||||||
this.searchClient = new JsApiAngularHttpClient(
|
|
||||||
config.hostEcm,
|
|
||||||
config.contextRoot,
|
|
||||||
`/api/${config.tenant}/public/search/versions/1`,
|
|
||||||
this.httpClient
|
|
||||||
);
|
|
||||||
this.discoveryClient = new JsApiAngularHttpClient(
|
|
||||||
config.hostEcm,
|
|
||||||
config.contextRoot,
|
|
||||||
`/api`,
|
|
||||||
this.httpClient
|
|
||||||
);
|
|
||||||
|
|
||||||
this.gsClient = new JsApiAngularHttpClient(
|
|
||||||
config.hostEcm,
|
|
||||||
config.contextRoot,
|
|
||||||
`/api/${config.tenant}/public/gs/versions/1`,
|
|
||||||
this.httpClient
|
|
||||||
);
|
|
||||||
|
|
||||||
this.processClient = new JsApiAngularHttpClient(
|
|
||||||
config.hostBpm,
|
|
||||||
config.contextRootBpm,
|
|
||||||
'',
|
|
||||||
this.httpClient
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
236
lib/core/alfresco-api/services/alfresco-api-v2.ts
Normal file
236
lib/core/alfresco-api/services/alfresco-api-v2.ts
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*tslint:disable*/ // => because of ADF file naming problems... Try to remove it, if you don't believe me :P
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import { AlfrescoApiConfig } from '@alfresco/js-api';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { JsApiHttpClient } from '../js-api/js-api-http-client';
|
||||||
|
import { JsApiAngularHttpClient } from './js-api-angular-http-client';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { AlfrescoApiType, LegacyTicketApi } from '../js-api/alfresco-api-type';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AlfrescoApiV2 implements AlfrescoApiType {
|
||||||
|
public config: AlfrescoApiConfig;
|
||||||
|
public contentPrivateClient: JsApiHttpClient & LegacyTicketApi;
|
||||||
|
public contentClient: JsApiHttpClient & LegacyTicketApi;
|
||||||
|
public authClient: JsApiHttpClient;
|
||||||
|
public searchClient: JsApiHttpClient;
|
||||||
|
public discoveryClient: JsApiHttpClient;
|
||||||
|
public gsClient: JsApiHttpClient;
|
||||||
|
public processClient: JsApiHttpClient;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private httpClient: HttpClient
|
||||||
|
) {}
|
||||||
|
|
||||||
|
init(config: AlfrescoApiConfig) {
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
|
this.contentPrivateClient = new JsApiAngularHttpClient(
|
||||||
|
config.hostEcm,
|
||||||
|
config.contextRoot,
|
||||||
|
`/api/${config.tenant}/private/alfresco/versions/1`,
|
||||||
|
this.httpClient
|
||||||
|
) as unknown as JsApiHttpClient & LegacyTicketApi;
|
||||||
|
|
||||||
|
this.contentClient = new JsApiAngularHttpClient(
|
||||||
|
config.hostEcm,
|
||||||
|
config.contextRoot,
|
||||||
|
`/api/${config.tenant}/public/alfresco/versions/1`,
|
||||||
|
this.httpClient
|
||||||
|
) as unknown as JsApiHttpClient & LegacyTicketApi;
|
||||||
|
|
||||||
|
this.authClient = new JsApiAngularHttpClient(
|
||||||
|
config.hostEcm,
|
||||||
|
config.contextRoot,
|
||||||
|
`/api/${config.tenant}/public/authentication/versions/1`,
|
||||||
|
this.httpClient
|
||||||
|
);
|
||||||
|
|
||||||
|
this.searchClient = new JsApiAngularHttpClient(
|
||||||
|
config.hostEcm,
|
||||||
|
config.contextRoot,
|
||||||
|
`/api/${config.tenant}/public/search/versions/1`,
|
||||||
|
this.httpClient
|
||||||
|
);
|
||||||
|
this.discoveryClient = new JsApiAngularHttpClient(
|
||||||
|
config.hostEcm,
|
||||||
|
config.contextRoot,
|
||||||
|
`/api`,
|
||||||
|
this.httpClient
|
||||||
|
);
|
||||||
|
|
||||||
|
this.gsClient = new JsApiAngularHttpClient(
|
||||||
|
config.hostEcm,
|
||||||
|
config.contextRoot,
|
||||||
|
`/api/${config.tenant}/public/gs/versions/1`,
|
||||||
|
this.httpClient
|
||||||
|
);
|
||||||
|
|
||||||
|
this.processClient = new JsApiAngularHttpClient(
|
||||||
|
config.hostBpm,
|
||||||
|
config.contextRootBpm,
|
||||||
|
'',
|
||||||
|
this.httpClient
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfig(config: AlfrescoApiConfig) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeWithCredentialsConfig(withCredentials: boolean) {
|
||||||
|
console.log(withCredentials);
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeCsrfConfig(disableCsrf: boolean) {
|
||||||
|
console.log(disableCsrf);
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeEcmHost(hostEcm: string) {
|
||||||
|
console.log(hostEcm);
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeBpmHost(hostBpm: string) {
|
||||||
|
console.log(hostBpm);
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
login(username: string, password: string) {
|
||||||
|
console.log(username, password);
|
||||||
|
debugger;
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
isCredentialValid(credential: string) {
|
||||||
|
console.log(credential);
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitLogin() {
|
||||||
|
debugger;
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
loginTicket(ticketEcm: string, ticketBpm: string) {
|
||||||
|
console.log(ticketEcm, ticketBpm);
|
||||||
|
debugger;
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
debugger;
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoggedIn() {
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isBpmLoggedIn() {
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEcmLoggedIn() {
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBpmUsername() {
|
||||||
|
debugger;
|
||||||
|
return 'Kakarot';
|
||||||
|
}
|
||||||
|
|
||||||
|
getEcmUsername() {
|
||||||
|
debugger;
|
||||||
|
return 'Vegeta';
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshToken() {
|
||||||
|
debugger;
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
getTicketAuth() {
|
||||||
|
debugger;
|
||||||
|
return 'xyz-123';
|
||||||
|
}
|
||||||
|
|
||||||
|
setTicket(ticketEcm: string, TicketBpm: string) {
|
||||||
|
console.log(ticketEcm, TicketBpm);
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidateSession() {
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTicketBpm() {
|
||||||
|
debugger;
|
||||||
|
return 'xyz-456';
|
||||||
|
}
|
||||||
|
|
||||||
|
getTicketEcm() {
|
||||||
|
debugger;
|
||||||
|
return 'xyz-789';
|
||||||
|
}
|
||||||
|
|
||||||
|
getTicket() {
|
||||||
|
debugger;
|
||||||
|
return ['xyz-000'];
|
||||||
|
}
|
||||||
|
|
||||||
|
isBpmConfiguration() {
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEcmConfiguration() {
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isOauthConfiguration() {
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isPublicUrl() {
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEcmBpmConfiguration() {
|
||||||
|
debugger;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply(event: string, callback?: any) {
|
||||||
|
console.log(event, callback);
|
||||||
|
debugger;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*tslint:disable*/ // => because of ADF file naming problems... Try to remove it, if you don't believe me :P
|
||||||
|
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ReplaySubject } from 'rxjs/internal/ReplaySubject';
|
||||||
|
import { AlfrescoApiType } from '../js-api/alfresco-api-type';
|
||||||
|
import { AlfrescoApiV2 } from './alfresco-api-v2';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LegacyAlfrescoApiServiceFacade {
|
||||||
|
constructor(private alfrescoApiV2: AlfrescoApiV2) {}
|
||||||
|
|
||||||
|
alfrescoApiInitialized: ReplaySubject<boolean> = new ReplaySubject(1);
|
||||||
|
|
||||||
|
getInstance(): AlfrescoApiType {
|
||||||
|
return this.alfrescoApiV2;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.alfrescoApiInitialized.next(true);
|
||||||
|
}
|
||||||
|
}
|
25
lib/core/app-config/app-config.loader.ts
Normal file
25
lib/core/app-config/app-config.loader.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { StorageService } from '../services/storage.service';
|
||||||
|
import { AppConfigService, AppConfigValues } from './app-config.service';
|
||||||
|
|
||||||
|
export function loadAppConfig(appConfigService: AppConfigService, storageService: StorageService) {
|
||||||
|
return () => appConfigService.load().then(() => {
|
||||||
|
storageService.prefix = appConfigService.get<string>(AppConfigValues.STORAGE_PREFIX, '');
|
||||||
|
});
|
||||||
|
}
|
@ -16,8 +16,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { NgModule } from '@angular/core';
|
import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core';
|
||||||
|
import { StorageService } from '../services/storage.service';
|
||||||
|
import { loadAppConfig } from './app-config.loader';
|
||||||
import { AppConfigPipe } from './app-config.pipe';
|
import { AppConfigPipe } from './app-config.pipe';
|
||||||
|
import { AppConfigService } from './app-config.service';
|
||||||
|
|
||||||
|
interface AppConfigModuleConfig {
|
||||||
|
loadConfig: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultConfig: AppConfigModuleConfig = {
|
||||||
|
loadConfig: true
|
||||||
|
};
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -31,4 +42,18 @@ import { AppConfigPipe } from './app-config.pipe';
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppConfigModule {
|
export class AppConfigModule {
|
||||||
|
static forRoot(config: AppConfigModuleConfig = defaultConfig): ModuleWithProviders<AppConfigModule> {
|
||||||
|
return {
|
||||||
|
ngModule: AppConfigModule,
|
||||||
|
providers: [
|
||||||
|
...(config.loadConfig ?
|
||||||
|
[{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: loadAppConfig,
|
||||||
|
deps: [ AppConfigService, StorageService ], multi: true }
|
||||||
|
] : []
|
||||||
|
)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,8 +191,9 @@ export class AppConfigService {
|
|||||||
this.http.get(configUrl).subscribe(
|
this.http.get(configUrl).subscribe(
|
||||||
(data: any) => {
|
(data: any) => {
|
||||||
this.status = Status.LOADED;
|
this.status = Status.LOADED;
|
||||||
this.onDataLoaded(data);
|
|
||||||
resolve(this.config);
|
resolve(this.config);
|
||||||
|
// WARNING: Risky change! Despite the fact that this would be the right order, this is a breaking change...
|
||||||
|
this.onDataLoaded(data);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
resolve(this.config);
|
resolve(this.config);
|
||||||
|
60
lib/core/authentication/authentication.interface.ts
Normal file
60
lib/core/authentication/authentication.interface.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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, ReplaySubject } from 'rxjs';
|
||||||
|
import { RedirectionModel } from '../models/redirection.model';
|
||||||
|
import { PeopleApi, UserProfileApi, UserRepresentation } from '@alfresco/js-api';
|
||||||
|
import { HttpHeaders } from '@angular/common/http';
|
||||||
|
|
||||||
|
export interface ADFAuthenticationService {
|
||||||
|
onLogin: ReplaySubject<any>;
|
||||||
|
onLogout: ReplaySubject<any>;
|
||||||
|
|
||||||
|
peopleApi: PeopleApi;
|
||||||
|
profileApi: UserProfileApi;
|
||||||
|
|
||||||
|
isLoggedIn(): boolean;
|
||||||
|
isLoggedInWith(provider: string): boolean;
|
||||||
|
isKerberosEnabled(): boolean;
|
||||||
|
isOauth(): boolean;
|
||||||
|
oidcHandlerEnabled(): boolean;
|
||||||
|
isImplicitFlow(): boolean;
|
||||||
|
isAuthCodeFlow(): boolean;
|
||||||
|
isPublicUrl(): boolean;
|
||||||
|
isECMProvider(): boolean;
|
||||||
|
isBPMProvider(): boolean;
|
||||||
|
isALLProvider(): boolean;
|
||||||
|
login(username: string, password: string, rememberMe?: boolean): Observable<{ type: string; ticket: any }>;
|
||||||
|
ssoImplicitLogin(): void;
|
||||||
|
ssoCodeFlowLogin?(): void;
|
||||||
|
isRememberMeSet(): boolean;
|
||||||
|
logout(): Observable<any>;
|
||||||
|
getTicketEcm(): string | null;
|
||||||
|
getTicketBpm(): string | null;
|
||||||
|
getTicketEcmBase64(): string | null;
|
||||||
|
isEcmLoggedIn(): boolean;
|
||||||
|
isBpmLoggedIn(): boolean;
|
||||||
|
getEcmUsername(): string;
|
||||||
|
getBpmUsername(): string;
|
||||||
|
setRedirect(url: RedirectionModel): void;
|
||||||
|
getRedirect(): string;
|
||||||
|
getBpmLoggedUser(): Observable<UserRepresentation>;
|
||||||
|
handleError(error: any): Observable<any>;
|
||||||
|
getBearerExcludedUrls(): string[];
|
||||||
|
getToken(): string;
|
||||||
|
addTokenToHeader(headersArg?: HttpHeaders): Observable<HttpHeaders>;
|
||||||
|
}
|
46
lib/core/authentication/base-authentication.service.ts
Normal file
46
lib/core/authentication/base-authentication.service.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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, Observer } from 'rxjs';
|
||||||
|
import { HttpHeaders } from '@angular/common/http';
|
||||||
|
|
||||||
|
export abstract class BaseAuthenticationService {
|
||||||
|
protected bearerExcludedUrls: string[] = ['auth/realms', 'resources/', 'assets/'];
|
||||||
|
|
||||||
|
abstract getToken(): string;
|
||||||
|
|
||||||
|
getBearerExcludedUrls(): string[] {
|
||||||
|
return this.bearerExcludedUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
addTokenToHeader(headersArg?: HttpHeaders): Observable<HttpHeaders> {
|
||||||
|
return new Observable((observer: Observer<any>) => {
|
||||||
|
let headers = headersArg;
|
||||||
|
if (!headers) {
|
||||||
|
headers = new HttpHeaders();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const token: string = this.getToken();
|
||||||
|
headers = headers.set('Authorization', 'Bearer ' + token);
|
||||||
|
observer.next(headers);
|
||||||
|
observer.complete();
|
||||||
|
} catch (error) {
|
||||||
|
observer.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
21
lib/core/authentication/index.ts
Normal file
21
lib/core/authentication/index.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { OIDCAuthModule } from './oidc/oidc.module';
|
||||||
|
export { OIDCAuthGuard } from './oidc/oidc-auth.guard';
|
||||||
|
export { BaseAuthenticationService } from './base-authentication.service';
|
||||||
|
export { ADFAuthenticationService } from './authentication.interface';
|
55
lib/core/authentication/oidc/oidc-auth.guard.ts
Normal file
55
lib/core/authentication/oidc/oidc-auth.guard.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { Injectable } from '@angular/core';
|
||||||
|
import { CanActivate, CanActivateChild } from '@angular/router';
|
||||||
|
import { OAuthService } from 'angular-oauth2-oidc';
|
||||||
|
import { AuthenticationService } from '../../services/authentication.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OIDCAuthGuard implements CanActivate, CanActivateChild {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private authenticationService: AuthenticationService,
|
||||||
|
private oauthService: OAuthService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
canActivate(): boolean {
|
||||||
|
if (this.shouldBeBypassed()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.oauthService.hasValidAccessToken()) {
|
||||||
|
if (this.authenticationService.isAuthCodeFlow()) {
|
||||||
|
this.oauthService.initCodeFlow();
|
||||||
|
} else {
|
||||||
|
this.oauthService.initLoginFlow();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldBeBypassed() {
|
||||||
|
return !this.authenticationService.oidcHandlerEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
canActivateChild(): boolean {
|
||||||
|
return this.canActivate();
|
||||||
|
}
|
||||||
|
}
|
203
lib/core/authentication/oidc/oidc-authentication.service.ts
Normal file
203
lib/core/authentication/oidc/oidc-authentication.service.ts
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { Injectable } from '@angular/core';
|
||||||
|
import { Observable, from, throwError, ReplaySubject, of } from 'rxjs';
|
||||||
|
import { LogService } from '../../services/log.service';
|
||||||
|
import { RedirectionModel } from '../../models/redirection.model';
|
||||||
|
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
||||||
|
import { PeopleApi, UserProfileApi, UserRepresentation } from '@alfresco/js-api';
|
||||||
|
import { JwtHelperService } from '../../services/jwt-helper.service';
|
||||||
|
import { StorageService } from '../../services/storage.service';
|
||||||
|
import { OauthConfigModel } from '../../models/oauth-config.model';
|
||||||
|
import { BaseAuthenticationService } from '../base-authentication.service';
|
||||||
|
import { ADFAuthenticationService } from '../authentication.interface';
|
||||||
|
import { AlfrescoApiClientFactory } from '../../alfresco-api';
|
||||||
|
import { OAuthService } from 'angular-oauth2-oidc';
|
||||||
|
import minimatch from 'minimatch';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class OIDCAuthenticationService extends BaseAuthenticationService implements ADFAuthenticationService {
|
||||||
|
onLogin: ReplaySubject<any> = new ReplaySubject<any>(1);
|
||||||
|
onLogout: ReplaySubject<any> = new ReplaySubject<any>(1);
|
||||||
|
|
||||||
|
get peopleApi(): PeopleApi {
|
||||||
|
return this.alfrescoApiClientFactory.getPeopleApi();
|
||||||
|
}
|
||||||
|
get profileApi(): UserProfileApi {
|
||||||
|
return this.alfrescoApiClientFactory.getProfileApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private alfrescoApiClientFactory: AlfrescoApiClientFactory,
|
||||||
|
private appConfig: AppConfigService,
|
||||||
|
private storageService: StorageService,
|
||||||
|
private oauthService: OAuthService,
|
||||||
|
private logService: LogService) {
|
||||||
|
super();
|
||||||
|
// this.alfrescoApi.alfrescoApiInitialized.subscribe(() => {
|
||||||
|
// this.alfrescoApi.getInstance().reply('logged-in', () => {
|
||||||
|
// this.onLogin.next();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (this.isKerberosEnabled()) {
|
||||||
|
// this.loadUserDetails();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
// private loadUserDetails() {
|
||||||
|
// const ecmUser$ = from(this.peopleApi.getPerson('-me-'));
|
||||||
|
// const bpmUser$ = this.getBpmLoggedUser();
|
||||||
|
|
||||||
|
// if (this.isALLProvider()) {
|
||||||
|
// forkJoin([ecmUser$, bpmUser$]).subscribe(() => this.onLogin.next());
|
||||||
|
// } else if (this.isECMProvider()) {
|
||||||
|
// ecmUser$.subscribe(() => this.onLogin.next());
|
||||||
|
// } else {
|
||||||
|
// bpmUser$.subscribe(() => this.onLogin.next());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
isLoggedIn(): boolean {
|
||||||
|
return this.oauthService.hasValidAccessToken() && this.oauthService.hasValidIdToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoggedInWith(provider?: string): boolean {
|
||||||
|
console.log(provider);
|
||||||
|
return this.isLoggedIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
isKerberosEnabled(): boolean {
|
||||||
|
return this.appConfig.get<boolean>(AppConfigValues.AUTH_WITH_CREDENTIALS, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
isOauth(): boolean {
|
||||||
|
return this.appConfig.get(AppConfigValues.AUTHTYPE) === 'OAUTH';
|
||||||
|
}
|
||||||
|
|
||||||
|
oidcHandlerEnabled(): boolean {
|
||||||
|
const oauth2: OauthConfigModel = Object.assign({}, this.appConfig.get<OauthConfigModel>(AppConfigValues.OAUTHCONFIG, null));
|
||||||
|
return oauth2?.handler === 'oidc';
|
||||||
|
}
|
||||||
|
|
||||||
|
isImplicitFlow() {
|
||||||
|
const oauth2: OauthConfigModel = Object.assign({}, this.appConfig.get<OauthConfigModel>(AppConfigValues.OAUTHCONFIG, null));
|
||||||
|
return !!oauth2?.implicitFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
isAuthCodeFlow() {
|
||||||
|
const oauth2: OauthConfigModel = Object.assign({}, this.appConfig.get<OauthConfigModel>(AppConfigValues.OAUTHCONFIG, null));
|
||||||
|
return !!oauth2?.codeFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
isPublicUrl(): boolean {
|
||||||
|
const oauth2: OauthConfigModel = Object.assign({}, this.appConfig.get<OauthConfigModel>(AppConfigValues.OAUTHCONFIG, null));
|
||||||
|
const publicUrls = oauth2.publicUrls || [];
|
||||||
|
|
||||||
|
if (Array.isArray(publicUrls)) {
|
||||||
|
return publicUrls.length > 0 &&
|
||||||
|
publicUrls.some((urlPattern: string) => minimatch(window.location.href, urlPattern));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isECMProvider(): boolean {
|
||||||
|
return this.appConfig.get<string>(AppConfigValues.PROVIDERS).toUpperCase() === 'ECM';
|
||||||
|
}
|
||||||
|
isBPMProvider(): boolean {
|
||||||
|
return this.appConfig.get<string>(AppConfigValues.PROVIDERS).toUpperCase() === 'BPM';
|
||||||
|
}
|
||||||
|
|
||||||
|
isALLProvider(): boolean {
|
||||||
|
return this.appConfig.get<string>(AppConfigValues.PROVIDERS).toUpperCase() === 'ALL';
|
||||||
|
}
|
||||||
|
|
||||||
|
login(): Observable<{ type: string; ticket: any }> {
|
||||||
|
return of();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssoImplicitLogin() {
|
||||||
|
this.oauthService.initLoginFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssoCodeFlowLogin() {
|
||||||
|
this.oauthService.initCodeFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
isRememberMeSet(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.oauthService.logOut();
|
||||||
|
return of();
|
||||||
|
}
|
||||||
|
|
||||||
|
getTicketEcm(): string | null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTicketBpm(): string | null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTicketEcmBase64(): string | null {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
isEcmLoggedIn(): boolean {
|
||||||
|
return this.isLoggedIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
isBpmLoggedIn(): boolean {
|
||||||
|
return this.isLoggedIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
getEcmUsername(): string {
|
||||||
|
return 'To Be Implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
getBpmUsername(): string {
|
||||||
|
return 'To Be Implemented';
|
||||||
|
}
|
||||||
|
|
||||||
|
setRedirect(url?: RedirectionModel) {
|
||||||
|
console.log(url);
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
getRedirect(): string {
|
||||||
|
// noop
|
||||||
|
return 'noop';
|
||||||
|
}
|
||||||
|
|
||||||
|
getBpmLoggedUser(): Observable<UserRepresentation> {
|
||||||
|
return from(this.profileApi.getProfile());
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError(error: any): Observable<any> {
|
||||||
|
this.logService.error('Error when logging in', error);
|
||||||
|
return throwError(error || 'Server error');
|
||||||
|
}
|
||||||
|
|
||||||
|
getToken(): string {
|
||||||
|
return this.storageService.getItem(JwtHelperService.USER_ACCESS_TOKEN);
|
||||||
|
}
|
||||||
|
}
|
78
lib/core/authentication/oidc/oidc-authentication.ts
Normal file
78
lib/core/authentication/oidc/oidc-authentication.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { Injectable } from '@angular/core';
|
||||||
|
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
|
||||||
|
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
|
||||||
|
import { OauthConfigModel } from '../../models/oauth-config.model';
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { StorageService } from '../../services/storage.service';
|
||||||
|
import { AuthenticationService } from '../../services/authentication.service';
|
||||||
|
|
||||||
|
export const configureOIDCAuthentication = (oidcAuthentication: OIDCAuthentication) => () => oidcAuthentication.init();
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OIDCAuthentication {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private appConfigService: AppConfigService,
|
||||||
|
private storageService: StorageService,
|
||||||
|
private authenticationService: AuthenticationService,
|
||||||
|
private oauthService: OAuthService,
|
||||||
|
private router: Router
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
this.appConfigService.onLoad
|
||||||
|
.pipe(take(1))
|
||||||
|
.toPromise()
|
||||||
|
.then(this.configure.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private configure() {
|
||||||
|
if (this.authenticationService.oidcHandlerEnabled()) {
|
||||||
|
const authConfig = this.getAuthConfig(this.authenticationService.isAuthCodeFlow());
|
||||||
|
this.oauthService.configure(authConfig);
|
||||||
|
this.oauthService.tokenValidationHandler = new JwksValidationHandler();
|
||||||
|
this.oauthService.setStorage(this.storageService);
|
||||||
|
this.oauthService.setupAutomaticSilentRefresh();
|
||||||
|
|
||||||
|
// This is what deald with the responded code and does the magic
|
||||||
|
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(() => {
|
||||||
|
// initialNavigation: false needs because of the OIDC package!!!
|
||||||
|
// https://manfredsteyer.github.io/angular-oauth2-oidc/docs/additional-documentation/routing-with-the-hashstrategy.html
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAuthConfig(codeFlow = false): AuthConfig {
|
||||||
|
const oauth2: OauthConfigModel = Object.assign({}, this.appConfigService.get<OauthConfigModel>(AppConfigValues.OAUTHCONFIG, null));
|
||||||
|
return {
|
||||||
|
issuer: oauth2.host,
|
||||||
|
loginUrl: `${oauth2.host}/protocol/openid-connect/auth`,
|
||||||
|
silentRefreshRedirectUri: oauth2.redirectSilentIframeUri,
|
||||||
|
redirectUri: window.location.origin + oauth2.redirectUri,
|
||||||
|
postLogoutRedirectUri: window.location.origin + oauth2.redirectUriLogout,
|
||||||
|
clientId: oauth2.clientId,
|
||||||
|
scope: oauth2.scope,
|
||||||
|
...(codeFlow ? { responseType: 'code' } : {})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
44
lib/core/authentication/oidc/oidc.module.ts
Normal file
44
lib/core/authentication/oidc/oidc.module.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright 2019 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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||||
|
import { OAuthModule } from 'angular-oauth2-oidc';
|
||||||
|
import { AuthenticationService } from '../../services';
|
||||||
|
import { OIDCAuthGuard } from './oidc-auth.guard';
|
||||||
|
import { OIDCAuthentication, configureOIDCAuthentication } from './oidc-authentication';
|
||||||
|
import { OIDCAuthenticationService } from './oidc-authentication.service';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
OAuthModule.forRoot()
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
OIDCAuthGuard,
|
||||||
|
OIDCAuthentication,
|
||||||
|
OIDCAuthenticationService,
|
||||||
|
{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: configureOIDCAuthentication,
|
||||||
|
deps: [ OIDCAuthentication ], multi: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: AuthenticationService,
|
||||||
|
useExisting: OIDCAuthenticationService
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class OIDCAuthModule {}
|
@ -60,6 +60,14 @@ import { DirectionalityConfigService } from './services/directionality-config.se
|
|||||||
import { SearchTextModule } from './search-text/search-text-input.module';
|
import { SearchTextModule } from './search-text/search-text-input.module';
|
||||||
import { versionCompatibilityFactory } from './services/version-compatibility-factory';
|
import { versionCompatibilityFactory } from './services/version-compatibility-factory';
|
||||||
import { VersionCompatibilityService } from './services/version-compatibility.service';
|
import { VersionCompatibilityService } from './services/version-compatibility.service';
|
||||||
|
|
||||||
|
interface MonolithCoreModuleConfig {
|
||||||
|
legacyAlfrescoApiService: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultConfig: MonolithCoreModuleConfig = {
|
||||||
|
legacyAlfrescoApiService: true
|
||||||
|
};
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
@ -133,21 +141,20 @@ import { VersionCompatibilityService } from './services/version-compatibility.se
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CoreModule {
|
export class CoreModule {
|
||||||
static forRoot(): ModuleWithProviders<CoreModule> {
|
static forRoot(config: MonolithCoreModuleConfig = defaultConfig): ModuleWithProviders<CoreModule> {
|
||||||
return {
|
return {
|
||||||
ngModule: CoreModule,
|
ngModule: CoreModule,
|
||||||
providers: [
|
providers: [
|
||||||
TranslateStore,
|
TranslateStore,
|
||||||
TranslateService,
|
TranslateService,
|
||||||
{ provide: TranslateLoader, useClass: TranslateLoaderService },
|
{ provide: TranslateLoader, useClass: TranslateLoaderService },
|
||||||
{
|
...(config.legacyAlfrescoApiService ?
|
||||||
provide: APP_INITIALIZER,
|
[{
|
||||||
useFactory: startupServiceFactory,
|
provide: APP_INITIALIZER,
|
||||||
deps: [
|
useFactory: startupServiceFactory,
|
||||||
AlfrescoApiService
|
deps: [ AlfrescoApiService ], multi: true }
|
||||||
],
|
] : []
|
||||||
multi: true
|
),
|
||||||
},
|
|
||||||
{
|
{
|
||||||
provide: APP_INITIALIZER,
|
provide: APP_INITIALIZER,
|
||||||
useFactory: directionalityConfigFactory,
|
useFactory: directionalityConfigFactory,
|
||||||
|
@ -16,14 +16,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export interface OauthConfigModel {
|
export interface OauthConfigModel {
|
||||||
|
handler?: 'legacy' | 'oidc';
|
||||||
host: string;
|
host: string;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
scope: string;
|
scope: string;
|
||||||
implicitFlow: boolean;
|
implicitFlow: boolean;
|
||||||
|
codeFlow?: boolean;
|
||||||
redirectUri: string;
|
redirectUri: string;
|
||||||
silentLogin?: boolean;
|
silentLogin?: boolean;
|
||||||
secret?: string;
|
secret?: string;
|
||||||
redirectUriLogout?: string;
|
redirectUriLogout?: string;
|
||||||
|
redirectSilentIframeUri?: string;
|
||||||
refreshTokenTimeout?: number;
|
refreshTokenTimeout?: number;
|
||||||
publicUrls: string[];
|
publicUrls: string[];
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,9 @@ export abstract class AuthGuardBase implements CanActivate, CanActivateChild {
|
|||||||
route: ActivatedRouteSnapshot,
|
route: ActivatedRouteSnapshot,
|
||||||
state: RouterStateSnapshot
|
state: RouterStateSnapshot
|
||||||
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
||||||
|
if (this.shouldBeBypassed()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.authenticationService.isLoggedIn() && this.authenticationService.isOauth() && this.isLoginFragmentPresent()) {
|
if (this.authenticationService.isLoggedIn() && this.authenticationService.isOauth() && this.isLoginFragmentPresent()) {
|
||||||
return this.redirectSSOSuccessURL();
|
return this.redirectSSOSuccessURL();
|
||||||
@ -75,6 +78,10 @@ export abstract class AuthGuardBase implements CanActivate, CanActivateChild {
|
|||||||
return this.canActivate(route, state);
|
return this.canActivate(route, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldBeBypassed() {
|
||||||
|
return this.authenticationService.oidcHandlerEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
protected async redirectSSOSuccessURL(): Promise<boolean | UrlTree> {
|
protected async redirectSSOSuccessURL(): Promise<boolean | UrlTree> {
|
||||||
const redirectFragment = this.storageService.getItem('loginFragment');
|
const redirectFragment = this.storageService.getItem('loginFragment');
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Observable, from, throwError, Observer, ReplaySubject, forkJoin } from 'rxjs';
|
import { Observable, from, throwError, ReplaySubject, forkJoin } from 'rxjs';
|
||||||
import { AlfrescoApiService } from './alfresco-api.service';
|
import { AlfrescoApiService } from './alfresco-api.service';
|
||||||
import { CookieService } from './cookie.service';
|
import { CookieService } from './cookie.service';
|
||||||
import { LogService } from './log.service';
|
import { LogService } from './log.service';
|
||||||
@ -24,9 +24,11 @@ import { RedirectionModel } from '../models/redirection.model';
|
|||||||
import { AppConfigService, AppConfigValues } from '../app-config/app-config.service';
|
import { AppConfigService, AppConfigValues } from '../app-config/app-config.service';
|
||||||
import { PeopleApi, UserProfileApi, UserRepresentation } from '@alfresco/js-api';
|
import { PeopleApi, UserProfileApi, UserRepresentation } from '@alfresco/js-api';
|
||||||
import { map, catchError, tap } from 'rxjs/operators';
|
import { map, catchError, tap } from 'rxjs/operators';
|
||||||
import { HttpHeaders } from '@angular/common/http';
|
|
||||||
import { JwtHelperService } from './jwt-helper.service';
|
import { JwtHelperService } from './jwt-helper.service';
|
||||||
import { StorageService } from './storage.service';
|
import { StorageService } from './storage.service';
|
||||||
|
import { OauthConfigModel } from '../models/oauth-config.model';
|
||||||
|
import { BaseAuthenticationService } from '../authentication/base-authentication.service';
|
||||||
|
import { ADFAuthenticationService } from '../authentication/authentication.interface';
|
||||||
|
|
||||||
const REMEMBER_ME_COOKIE_KEY = 'ALFRESCO_REMEMBER_ME';
|
const REMEMBER_ME_COOKIE_KEY = 'ALFRESCO_REMEMBER_ME';
|
||||||
const REMEMBER_ME_UNTIL = 1000 * 60 * 60 * 24 * 30;
|
const REMEMBER_ME_UNTIL = 1000 * 60 * 60 * 24 * 30;
|
||||||
@ -34,10 +36,9 @@ const REMEMBER_ME_UNTIL = 1000 * 60 * 60 * 24 * 30;
|
|||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class AuthenticationService {
|
export class AuthenticationService extends BaseAuthenticationService implements ADFAuthenticationService {
|
||||||
private redirectUrl: RedirectionModel = null;
|
private redirectUrl: RedirectionModel = null;
|
||||||
|
|
||||||
private bearerExcludedUrls: string[] = ['auth/realms', 'resources/', 'assets/'];
|
|
||||||
/**
|
/**
|
||||||
* Emits login event
|
* Emits login event
|
||||||
*/
|
*/
|
||||||
@ -66,15 +67,16 @@ export class AuthenticationService {
|
|||||||
private alfrescoApi: AlfrescoApiService,
|
private alfrescoApi: AlfrescoApiService,
|
||||||
private cookie: CookieService,
|
private cookie: CookieService,
|
||||||
private logService: LogService) {
|
private logService: LogService) {
|
||||||
this.alfrescoApi.alfrescoApiInitialized.subscribe(() => {
|
super();
|
||||||
this.alfrescoApi.getInstance().reply('logged-in', () => {
|
this.alfrescoApi.alfrescoApiInitialized.subscribe(() => {
|
||||||
this.onLogin.next();
|
this.alfrescoApi.getInstance().reply('logged-in', () => {
|
||||||
});
|
this.onLogin.next();
|
||||||
|
});
|
||||||
|
|
||||||
if (this.isKerberosEnabled()) {
|
if (this.isKerberosEnabled()) {
|
||||||
this.loadUserDetails();
|
this.loadUserDetails();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadUserDetails() {
|
private loadUserDetails() {
|
||||||
@ -127,7 +129,20 @@ export class AuthenticationService {
|
|||||||
* @returns True if supported, false otherwise
|
* @returns True if supported, false otherwise
|
||||||
*/
|
*/
|
||||||
isOauth(): boolean {
|
isOauth(): boolean {
|
||||||
return this.alfrescoApi.getInstance().isOauthConfiguration();
|
return this?.alfrescoApi?.getInstance()?.isOauthConfiguration() || this.appConfig.get(AppConfigValues.AUTHTYPE) === 'OAUTH';
|
||||||
|
}
|
||||||
|
|
||||||
|
oidcHandlerEnabled(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isImplicitFlow(): boolean {
|
||||||
|
const oauth2: OauthConfigModel = Object.assign({}, this.appConfig.get<OauthConfigModel>(AppConfigValues.OAUTHCONFIG, null));
|
||||||
|
return !!oauth2?.implicitFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
isAuthCodeFlow(): boolean {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
isPublicUrl(): boolean {
|
isPublicUrl(): boolean {
|
||||||
@ -140,7 +155,8 @@ export class AuthenticationService {
|
|||||||
* @returns True if supported, false otherwise
|
* @returns True if supported, false otherwise
|
||||||
*/
|
*/
|
||||||
isECMProvider(): boolean {
|
isECMProvider(): boolean {
|
||||||
return this.alfrescoApi.getInstance().isEcmConfiguration();
|
return this?.alfrescoApi?.getInstance()?.isEcmConfiguration() ||
|
||||||
|
this.appConfig.get<string>(AppConfigValues.PROVIDERS).toUpperCase() === 'ECM';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,7 +165,8 @@ export class AuthenticationService {
|
|||||||
* @returns True if supported, false otherwise
|
* @returns True if supported, false otherwise
|
||||||
*/
|
*/
|
||||||
isBPMProvider(): boolean {
|
isBPMProvider(): boolean {
|
||||||
return this.alfrescoApi.getInstance().isBpmConfiguration();
|
return this?.alfrescoApi?.getInstance()?.isBpmConfiguration() ||
|
||||||
|
this.appConfig.get<string>(AppConfigValues.PROVIDERS).toUpperCase() === 'BPM';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -158,7 +175,8 @@ export class AuthenticationService {
|
|||||||
* @returns True if both are supported, false otherwise
|
* @returns True if both are supported, false otherwise
|
||||||
*/
|
*/
|
||||||
isALLProvider(): boolean {
|
isALLProvider(): boolean {
|
||||||
return this.alfrescoApi.getInstance().isEcmBpmConfiguration();
|
return this?.alfrescoApi?.getInstance()?.isEcmBpmConfiguration() ||
|
||||||
|
this.appConfig.get<string>(AppConfigValues.PROVIDERS).toUpperCase() === 'ALL';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -364,15 +382,6 @@ export class AuthenticationService {
|
|||||||
return throwError(error || 'Server error');
|
return throwError(error || 'Server error');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the set of URLs that the token bearer is excluded from.
|
|
||||||
*
|
|
||||||
* @returns Array of URL strings
|
|
||||||
*/
|
|
||||||
getBearerExcludedUrls(): string[] {
|
|
||||||
return this.bearerExcludedUrls;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the auth token.
|
* Gets the auth token.
|
||||||
*
|
*
|
||||||
@ -381,27 +390,4 @@ export class AuthenticationService {
|
|||||||
getToken(): string {
|
getToken(): string {
|
||||||
return this.storageService.getItem(JwtHelperService.USER_ACCESS_TOKEN);
|
return this.storageService.getItem(JwtHelperService.USER_ACCESS_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the auth token to an HTTP header using the 'bearer' scheme.
|
|
||||||
*
|
|
||||||
* @param headersArg Header that will receive the token
|
|
||||||
* @returns The new header with the token added
|
|
||||||
*/
|
|
||||||
addTokenToHeader(headersArg?: HttpHeaders): Observable<HttpHeaders> {
|
|
||||||
return new Observable((observer: Observer<any>) => {
|
|
||||||
let headers = headersArg;
|
|
||||||
if (!headers) {
|
|
||||||
headers = new HttpHeaders();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const token: string = this.getToken();
|
|
||||||
headers = headers.set('Authorization', 'bearer ' + token);
|
|
||||||
observer.next(headers);
|
|
||||||
observer.complete();
|
|
||||||
} catch (error) {
|
|
||||||
observer.error(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,15 @@
|
|||||||
</mat-error>
|
</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="adf-full-width">
|
||||||
|
<mat-label>OAUTH2 Handler (legacy | oidc)</mat-label>
|
||||||
|
<input matInput name="handler" id="handler" formControlName="handler"
|
||||||
|
placeholder="legacy">
|
||||||
|
<mat-error *ngIf="handler.hasError('required')">
|
||||||
|
Error...
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<label for="silentLogin">{{ 'CORE.HOST_SETTINGS.SILENT'| translate }}</label>
|
<label for="silentLogin">{{ 'CORE.HOST_SETTINGS.SILENT'| translate }}</label>
|
||||||
<mat-slide-toggle class="adf-full-width" name="silentLogin" [color]="'primary'"
|
<mat-slide-toggle class="adf-full-width" name="silentLogin" [color]="'primary'"
|
||||||
formControlName="silentLogin">
|
formControlName="silentLogin">
|
||||||
@ -113,6 +122,11 @@
|
|||||||
formControlName="implicitFlow">
|
formControlName="implicitFlow">
|
||||||
</mat-slide-toggle>
|
</mat-slide-toggle>
|
||||||
|
|
||||||
|
<label for="implicitFlow">Auth code flow</label>
|
||||||
|
<mat-slide-toggle class="adf-full-width" name="codeFlow" [color]="'primary'"
|
||||||
|
formControlName="codeFlow">
|
||||||
|
</mat-slide-toggle>
|
||||||
|
|
||||||
|
|
||||||
<mat-form-field class="adf-full-width">
|
<mat-form-field class="adf-full-width">
|
||||||
<mat-label>{{ 'CORE.HOST_SETTINGS.REDIRECT'| translate }}</mat-label>
|
<mat-label>{{ 'CORE.HOST_SETTINGS.REDIRECT'| translate }}</mat-label>
|
||||||
|
@ -149,6 +149,8 @@ export class HostSettingsComponent implements OnInit {
|
|||||||
secret: oauth.secret,
|
secret: oauth.secret,
|
||||||
silentLogin: oauth.silentLogin,
|
silentLogin: oauth.silentLogin,
|
||||||
implicitFlow: oauth.implicitFlow,
|
implicitFlow: oauth.implicitFlow,
|
||||||
|
codeFlow: oauth.codeFlow,
|
||||||
|
handler: oauth.handler,
|
||||||
publicUrls: [oauth.publicUrls]
|
publicUrls: [oauth.publicUrls]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -263,10 +265,18 @@ export class HostSettingsComponent implements OnInit {
|
|||||||
return this.oauthConfig.get('secretId') as FormControl;
|
return this.oauthConfig.get('secretId') as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get handler(): FormControl {
|
||||||
|
return this.oauthConfig.get('handler') as FormControl;
|
||||||
|
}
|
||||||
|
|
||||||
get implicitFlow(): FormControl {
|
get implicitFlow(): FormControl {
|
||||||
return this.oauthConfig.get('implicitFlow') as FormControl;
|
return this.oauthConfig.get('implicitFlow') as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get codeFlow(): FormControl {
|
||||||
|
return this.oauthConfig.get('codeFlow') as FormControl;
|
||||||
|
}
|
||||||
|
|
||||||
get silentLogin(): FormControl {
|
get silentLogin(): FormControl {
|
||||||
return this.oauthConfig.get('silentLogin') as FormControl;
|
return this.oauthConfig.get('silentLogin') as FormControl;
|
||||||
}
|
}
|
||||||
|
40
package-lock.json
generated
40
package-lock.json
generated
@ -24658,6 +24658,24 @@
|
|||||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
|
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"angular-oauth2-oidc": {
|
||||||
|
"version": "12.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/angular-oauth2-oidc/-/angular-oauth2-oidc-12.1.0.tgz",
|
||||||
|
"integrity": "sha512-YUsNTWx8lccgo4e3qHvqJ6DOR9nfPVd+riyXzcy5nI4CB9cc2+SxaxiqQMGPAaKI2EOIfdxNobmUqUSEO+IXxA==",
|
||||||
|
"requires": {
|
||||||
|
"fast-sha256": "^1.3.0",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"angular-oauth2-oidc-jwks": {
|
||||||
|
"version": "12.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/angular-oauth2-oidc-jwks/-/angular-oauth2-oidc-jwks-12.0.0.tgz",
|
||||||
|
"integrity": "sha512-9zXnzQD5yCsmMhL0lk8YOgn74TUNeeB9dpO6QhxQnO9vnjfZetu4j3TMFd4Hvo7s8WmCN6bzycapp2Qh6NN8vw==",
|
||||||
|
"requires": {
|
||||||
|
"jsrsasign": "^10.3.0",
|
||||||
|
"tslib": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ansi-align": {
|
"ansi-align": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
|
||||||
@ -31264,9 +31282,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "17.0.8",
|
"version": "17.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.9.tgz",
|
||||||
"integrity": "sha512-wDeUwiUmem9FzsyysEwRukaEdDNcwbROvQ9QGRKaLI6t+IltNzbn4/i4asmB10auvZGQCzSQ6t0GSczEThlUXw==",
|
"integrity": "sha512-Ci8+4/DOtkHRylcisKmVMtmVO5g7weUVCKcsu1sJvF1bn0wExTmbHmhFKj7AnEm0de800iovGhdSKzYnzbaHpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
@ -31661,9 +31679,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/yargs": {
|
"@types/yargs": {
|
||||||
"version": "17.0.8",
|
"version": "17.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.9.tgz",
|
||||||
"integrity": "sha512-wDeUwiUmem9FzsyysEwRukaEdDNcwbROvQ9QGRKaLI6t+IltNzbn4/i4asmB10auvZGQCzSQ6t0GSczEThlUXw==",
|
"integrity": "sha512-Ci8+4/DOtkHRylcisKmVMtmVO5g7weUVCKcsu1sJvF1bn0wExTmbHmhFKj7AnEm0de800iovGhdSKzYnzbaHpg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/yargs-parser": "*"
|
"@types/yargs-parser": "*"
|
||||||
@ -32552,6 +32570,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
||||||
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
|
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
|
||||||
},
|
},
|
||||||
|
"fast-sha256": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="
|
||||||
|
},
|
||||||
"fastest-levenshtein": {
|
"fastest-levenshtein": {
|
||||||
"version": "1.0.12",
|
"version": "1.0.12",
|
||||||
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
|
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
|
||||||
@ -38296,6 +38319,11 @@
|
|||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jsrsasign": {
|
||||||
|
"version": "10.5.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.8.tgz",
|
||||||
|
"integrity": "sha512-ewFUGPZJujIR9j84Q5LEzPTG4D1qQZ4CjJrgHfMEAAiArkC3xfdgNP0ZAXXxXbb+K8Phw15soOIJ8bX3+usEdQ=="
|
||||||
|
},
|
||||||
"jszip": {
|
"jszip": {
|
||||||
"version": "3.7.1",
|
"version": "3.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz",
|
||||||
|
@ -88,6 +88,8 @@
|
|||||||
"@mat-datetimepicker/moment": "^5.1.1",
|
"@mat-datetimepicker/moment": "^5.1.1",
|
||||||
"@ngx-translate/core": "^13.0.0",
|
"@ngx-translate/core": "^13.0.0",
|
||||||
"adf-tslint-rules": "0.0.7",
|
"adf-tslint-rules": "0.0.7",
|
||||||
|
"angular-oauth2-oidc": "^12.1.0",
|
||||||
|
"angular-oauth2-oidc-jwks": "^12.0.0",
|
||||||
"apollo-angular": "^2.6.0",
|
"apollo-angular": "^2.6.0",
|
||||||
"chart.js": "2.9.4",
|
"chart.js": "2.9.4",
|
||||||
"classlist.js": "1.1.20150312",
|
"classlist.js": "1.1.20150312",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user