From 7b2034282d9ec9d1679e06f7a4dc1cb47f635848 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Fri, 29 Nov 2019 14:41:47 +0000 Subject: [PATCH 01/10] Add support for setup UI for local admin account --- .../packages/core/sass/_all-theme.scss | 2 +- src/frontend/packages/core/src/app.routing.ts | 21 ++++- .../login/login-page/login-page.component.ts | 2 +- .../local-account-wizard.component.html | 31 +++++++ .../local-account-wizard.component.scss | 74 ++++++++++++++++ .../local-account-wizard.component.spec.ts | 25 ++++++ .../local-account-wizard.component.ts | 87 +++++++++++++++++++ .../setup-welcome.component.html | 23 +++++ .../setup-welcome.component.scss | 74 ++++++++++++++++ .../setup-welcome.component.spec.ts | 25 ++++++ .../setup-welcome/setup-welcome.component.ts | 49 +++++++++++ .../core/src/features/setup/setup.module.ts | 6 +- .../console-uaa-wizard.component.html | 17 +--- .../page-header/page-header.component.ts | 2 +- .../tile-selector-tile.component.html | 13 +++ .../tile-selector-tile.component.scss | 74 ++++++++++++++++ .../tile-selector-tile.component.spec.ts | 25 ++++++ .../tile-selector-tile.component.theme.scss} | 0 .../tile-selector-tile.component.ts | 21 +++++ .../tile-selector.component.html | 17 +--- .../tile-selector.component.scss | 66 -------------- .../components/tile/tile-selector.types.ts | 3 +- .../packages/core/src/shared/shared.module.ts | 5 +- .../store/src/actions/setup.actions.ts | 4 +- .../store/src/effects/uaa-setup.effects.ts | 65 +++++++------- .../store/src/types/uaa-setup.types.ts | 4 + src/jetstream/auth.go | 8 ++ src/jetstream/default.config.properties | 10 +-- src/jetstream/main.go | 28 +++--- src/jetstream/setup_console.go | 51 ++++++++++- 30 files changed, 675 insertions(+), 157 deletions(-) create mode 100644 src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.html create mode 100644 src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.scss create mode 100644 src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.spec.ts create mode 100644 src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.ts create mode 100644 src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.html create mode 100644 src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.scss create mode 100644 src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.spec.ts create mode 100644 src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.ts create mode 100644 src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html create mode 100644 src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.scss create mode 100644 src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.spec.ts rename src/frontend/packages/core/src/shared/components/{tile-selector/tile-selector.component.theme.scss => tile-selector-tile/tile-selector-tile.component.theme.scss} (100%) create mode 100644 src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.ts diff --git a/src/frontend/packages/core/sass/_all-theme.scss b/src/frontend/packages/core/sass/_all-theme.scss index 184dc594e9..702e3cbe31 100644 --- a/src/frontend/packages/core/sass/_all-theme.scss +++ b/src/frontend/packages/core/sass/_all-theme.scss @@ -35,7 +35,7 @@ @import '../src/shared/components/start-end-date/start-end-date.component.theme'; @import '../src/shared/components/metrics-chart/metrics-chart.component.theme'; @import '../src/shared/components/metrics-range-selector/metrics-range-selector.component.theme'; -@import '../src/shared/components/tile-selector/tile-selector.component.theme'; +@import '../src/shared/components/tile-selector-tile/tile-selector-tile.component.theme'; @import '../src/shared/components/entity-summary-title/entity-summary-title.component.theme'; @import '../src/shared/components/multiline-title/multiline-title.component.theme'; @import '../src/features/user-profile/profile-info/profile-info.component.theme'; diff --git a/src/frontend/packages/core/src/app.routing.ts b/src/frontend/packages/core/src/app.routing.ts index ab43664263..224141905d 100644 --- a/src/frontend/packages/core/src/app.routing.ts +++ b/src/frontend/packages/core/src/app.routing.ts @@ -15,13 +15,28 @@ import { ConsoleUaaWizardComponent } from './features/setup/uaa-wizard/console-u import { UpgradePageComponent } from './features/setup/upgrade-page/upgrade-page.component'; import { SharedModule } from './shared/shared.module'; import { NotSetupGuardService } from './core/not-setup-guard.service'; +import { SetupWelcomeComponent } from './features/setup/setup-welcome/setup-welcome.component'; +import { LocalAccountWizardComponent } from './features/setup/local-account-wizard/local-account-wizard.component'; const appRoutes: Routes = [ { path: '', redirectTo: 'home', pathMatch: 'full' }, { - path: 'uaa', - component: ConsoleUaaWizardComponent, - canActivate: [NotSetupGuardService] + path: 'setup', + canActivate: [NotSetupGuardService], + children: [ + { + path: '', + component: SetupWelcomeComponent + }, + { + path: 'uaa', + component: ConsoleUaaWizardComponent + }, + { + path: 'local', + component: LocalAccountWizardComponent + }, + ] }, { path: 'upgrade', component: UpgradePageComponent }, { path: 'domainMismatch', component: DomainMismatchComponent }, diff --git a/src/frontend/packages/core/src/features/login/login-page/login-page.component.ts b/src/frontend/packages/core/src/features/login/login-page/login-page.component.ts index 5050708f80..8764ac68f0 100644 --- a/src/frontend/packages/core/src/features/login/login-page/login-page.component.ts +++ b/src/frontend/packages/core/src/features/login/login-page/login-page.component.ts @@ -124,7 +124,7 @@ export class LoginPageComponent implements OnInit, OnDestroy { // Setup mode if (auth.sessionData && auth.sessionData.uaaError) { this.subscription.unsubscribe(); // Ensure to unsub otherwise GoToState gets caught in loop - this.store.dispatch(new RouterNav({ path: ['/uaa'] })); + this.store.dispatch(new RouterNav({ path: ['/setup'] })); return false; } diff --git a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.html b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.html new file mode 100644 index 0000000000..e70dad051a --- /dev/null +++ b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.html @@ -0,0 +1,31 @@ +
+ +

Stratos Setup with Local Admin Account

+
+ +
+ + + +
+

+ Please choose a password to use for the local Administrator account.

+

This will configure Stratos with a single, built-in account with the username admin + and the password that you choose below.

+
+
+ + + + + + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.scss b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.scss new file mode 100644 index 0000000000..8ee24f82e9 --- /dev/null +++ b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.scss @@ -0,0 +1,74 @@ +.page-container { + display: flex; + flex-direction: column; + height: 100%; +} + +.uaa-wizard { + display: flex; + flex: 1; + margin: 0 100px; + &__form { + display: block; + flex-direction: column; + width: 100%; + } + &__form-block { + display: flex; + flex-direction: column; + margin-left: 36px; + } + &__form-section { + margin: 12px 0 6px; + } + &__intro { + font-size: 18px; + font-weight: 600; + padding-top: 36px; + } + &__form-username { + font-family: Source Code Pro; + font-weight: bold; + } + &__sso-block { + margin-left: 28px; + margin-top: 6px; + code { + font-size: 14px; + padding-left: 6px; + } + } + form { + min-width: 400px; + width: 100%; + + mat-checkbox { + padding: 6px 0; + } + } + app-steppers { + display: flex; + flex: 1; + margin: 24px 0; + > .steppers__wrapper { + flex: 1; + } + .stepper-form { + margin-top: 0; + max-width: none; + } + .mat-form-field { + max-width: 450px; + } + .steppers__contents { + margin: 0 48px; + overflow-y: auto; + } + .steppers__navigation { + margin-top: 36px; + } + } + app-stratos-title { + text-align: center; + } +} diff --git a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.spec.ts b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.spec.ts new file mode 100644 index 0000000000..21e620718a --- /dev/null +++ b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LocalAccountWizardComponent } from './local-account-wizard.component'; + +describe('LocalAccountWizardComponent', () => { + let component: LocalAccountWizardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ LocalAccountWizardComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LocalAccountWizardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.ts b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.ts new file mode 100644 index 0000000000..8574fd2020 --- /dev/null +++ b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.ts @@ -0,0 +1,87 @@ +import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormControl, Validators, ValidatorFn, AbstractControl } from '@angular/forms'; +import { Observable, BehaviorSubject, of as obsof } from 'rxjs'; +import { StepOnNextFunction } from '../../../shared/components/stepper/step/step.component'; +import { Store } from '@ngrx/store'; +import { InternalAppState } from '../../../../../store/src/app-state'; +import { SetupUAASave } from '../../../../../store/src/actions/setup.actions'; +import { filter, delay, take, map } from 'rxjs/operators'; +import { UAASetupState, LocalAdminSetupData } from '../../../../../store/src/types/uaa-setup.types'; +import { AuthState } from '../../../../../store/src/reducers/auth.reducer'; +import { VerifySession } from '../../../../../store/src/actions/auth.actions'; + +@Component({ + selector: 'app-local-account-wizard', + templateUrl: './local-account-wizard.component.html', + styleUrls: ['./local-account-wizard.component.scss'] +}) +export class LocalAccountWizardComponent implements OnInit { + + passwordForm: FormGroup; + validateUAAForm: Observable; + applyingSetup$ = new BehaviorSubject(false); + + constructor(private store: Store>) { } + + ngOnInit() { + this.passwordForm = new FormGroup({ + adminPassword: new FormControl('', [Validators.required as any]), + adminPasswordConfirm: new FormControl('', [Validators.required as any]) + }); + + let observer; + this.validateUAAForm = new Observable(o => { + observer = o; + observer.next(false); + }); + + this.passwordForm.valueChanges.subscribe(() => { + observer.next(this.passwordForm.valid); + this.passwordForm.controls.adminPasswordConfirm.setValidators([Validators.required, this.confirmPasswordValidator()]); + }); + } + + next: StepOnNextFunction = () => { + + const data: LocalAdminSetupData = { + local_admin_password: this.passwordForm.get('adminPassword').value, + }; + + this.applyingSetup$.next(true); + this.store.dispatch(new SetupUAASave(data)); + return this.store.select(s => [s.uaaSetup, s.auth]).pipe( + filter(([uaa, auth]: [UAASetupState, AuthState]) => { + return !(uaa.settingUp || auth.verifying); + }), + delay(3000), + take(10), + filter(([uaa, auth]: [UAASetupState, AuthState]) => { + const validUAASessionData = auth.sessionData && !auth.sessionData.uaaError; + if (!validUAASessionData) { + this.store.dispatch(new VerifySession()); + } + return validUAASessionData; + }), + map((state: [UAASetupState, AuthState]) => { + if (!state[0].error) { + // Do a hard reload of the app + const loc = window.location; + const reload = loc.protocol + '//' + loc.host; + window.location.assign(reload); + } else { + this.applyingSetup$.next(false); + } + return { + success: !state[0].error, + message: state[0].message + }; + })); + } + + confirmPasswordValidator(): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } => { + const same = control.value === this.passwordForm.value.adminPassword; + return same ? null : { passwordMatch: { value: control.value } }; + }; + } +} diff --git a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.html b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.html new file mode 100644 index 0000000000..24f403ddfc --- /dev/null +++ b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.html @@ -0,0 +1,23 @@ +
+ +

Stratos Setup

+
+ +
+ + +
+ +
+

Welcome to Stratos

+

Before you can login, you need to choose how users will login to Stratos and complete the required configuration for the chosen method of authenticaion:

+
+
+ + +
+
+
+
+
+
\ No newline at end of file diff --git a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.scss b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.scss new file mode 100644 index 0000000000..65961dffca --- /dev/null +++ b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.scss @@ -0,0 +1,74 @@ +@import '../../../../sass/mixins'; + +.page-container { + display: flex; + flex-direction: column; + height: 100%; +} + +.select-step { + width: calc(100vw - 320px); +} + +.setup-tiles { + + display: grid; + grid-column-gap: 10px; + grid-row-gap: 10px; + grid-template-columns: 100%; + margin: 0 10px; + + @include breakpoint(tablet) { + grid-column-gap: 10%; + grid-template-columns: repeat(2, 1fr); + margin: 0 5%; + } + +} + +.setup { + display: flex; + flex: 1; + margin: 0 100px; + + &__intro { + font-size: 28px; + font-weight: 600; + padding-bottom: 26px; + text-align: center; + } + + &__config { + margin-bottom: 40px; + padding: 10px; + } + + app-steppers { + display: flex; + flex: 1; + margin: 24px 0; + > .steppers__wrapper { + flex: 1; + width: 100%; + } + .stepper-form { + margin-top: 0; + max-width: none; + } + .mat-form-field { + max-width: 450px; + } + .steppers__contents { + margin: 0 48px; + overflow-y: auto; + } + .steppers__navigation { + margin-top: 36px; + } + } + + app-stratos-title { + text-align: center; + } + +} \ No newline at end of file diff --git a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.spec.ts b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.spec.ts new file mode 100644 index 0000000000..2a0a506ac2 --- /dev/null +++ b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SetupWelcomeComponent } from './setup-welcome.component'; + +describe('SetupWelcomeComponent', () => { + let component: SetupWelcomeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SetupWelcomeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SetupWelcomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.ts b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.ts new file mode 100644 index 0000000000..a4d53a1f38 --- /dev/null +++ b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.ts @@ -0,0 +1,49 @@ +import { Component } from '@angular/core'; +import { ITileConfig, ITileData } from '../../../shared/components/tile/tile-selector.types'; +import { Store } from '@ngrx/store'; +import { GeneralEntityAppState } from '../../../../../store/src/app-state'; +import { RouterNav } from '../../../../../store/src/actions/router.actions'; +import { BASE_REDIRECT_QUERY } from '../../../shared/components/stepper/stepper.types'; + +@Component({ + selector: 'app-setup-welcome', + templateUrl: './setup-welcome.component.html', + styleUrls: ['./setup-welcome.component.scss'] +}) +export class SetupWelcomeComponent { + + public tileSelectorConfig = [ + new ITileConfig( + 'Local Admin', + { matIcon: 'person' }, + { type: 'local' }, + false, + 'Use a built-in single Admin User account' + ), + new ITileConfig( + 'Cloud Foundry UAA', + { + location: '/core/assets/endpoint-icons/cloudfoundry.png', + }, + { type: 'uaa' }, + false, + 'Use a Cloud Foundry UAA for user authentication' + ) + + ]; + + constructor(public store: Store) {} + + public selectionChange(tile: ITileConfig) { + if (tile) { + this.store.dispatch(new RouterNav({ + path: `setup/${tile.data.type}`, + query: { + [BASE_REDIRECT_QUERY]: 'setup' + } + })); + } + } + + +} diff --git a/src/frontend/packages/core/src/features/setup/setup.module.ts b/src/frontend/packages/core/src/features/setup/setup.module.ts index baf36f0e90..14e18ec1a7 100644 --- a/src/frontend/packages/core/src/features/setup/setup.module.ts +++ b/src/frontend/packages/core/src/features/setup/setup.module.ts @@ -5,6 +5,8 @@ import { SharedModule } from '../../shared/shared.module'; import { ConsoleUaaWizardComponent } from './uaa-wizard/console-uaa-wizard.component'; import { UpgradePageComponent } from './upgrade-page/upgrade-page.component'; import { DomainMismatchComponent } from './domain-mismatch/domain-mismatch.component'; +import { SetupWelcomeComponent } from './setup-welcome/setup-welcome.component'; +import { LocalAccountWizardComponent } from './local-account-wizard/local-account-wizard.component'; @NgModule({ @@ -15,7 +17,9 @@ import { DomainMismatchComponent } from './domain-mismatch/domain-mismatch.compo declarations: [ ConsoleUaaWizardComponent, UpgradePageComponent, - DomainMismatchComponent + DomainMismatchComponent, + SetupWelcomeComponent, + LocalAccountWizardComponent ] }) export class SetupModule { } diff --git a/src/frontend/packages/core/src/features/setup/uaa-wizard/console-uaa-wizard.component.html b/src/frontend/packages/core/src/features/setup/uaa-wizard/console-uaa-wizard.component.html index 13333b5ec2..49819e93dc 100644 --- a/src/frontend/packages/core/src/features/setup/uaa-wizard/console-uaa-wizard.component.html +++ b/src/frontend/packages/core/src/features/setup/uaa-wizard/console-uaa-wizard.component.html @@ -1,25 +1,10 @@
-

Stratos Setup

+

Stratos Setup with Cloud Foundry UAA

- -
- -

Welcome to Stratos

-

- Stratos is an Open Source Web-based UI (Console) for managing Cloud Foundry. It allows users and - administrators to both manage applications running in the Cloud Foundry cluster and perform cluster - management - tasks. -

-

Before accessing Stratos for the first time some configuration information is required.

- -

Press NEXT to get started.

-
-

Please enter the following information to allow Stratos to authenticate diff --git a/src/frontend/packages/core/src/shared/components/page-header/page-header.component.ts b/src/frontend/packages/core/src/shared/components/page-header/page-header.component.ts index af846d0efc..e929cfa0af 100644 --- a/src/frontend/packages/core/src/shared/components/page-header/page-header.component.ts +++ b/src/frontend/packages/core/src/shared/components/page-header/page-header.component.ts @@ -165,7 +165,7 @@ export class PageHeaderComponent implements OnDestroy, AfterViewInit { this.actionsKey = this.route.snapshot.data ? this.route.snapshot.data.extensionsActionsKey : null; this.breadcrumbKey = route.snapshot.queryParams[BREADCRUMB_URL_PARAM] || null; this.username$ = store.select(s => s.auth).pipe( - map((auth: AuthState) => auth && auth.sessionData ? auth.sessionData.user.name : 'Unknown') + map((auth: AuthState) => auth && auth.sessionData && auth.sessionData.user ? auth.sessionData.user.name : 'Unknown') ); this.userNameFirstLetter$ = this.username$.pipe( map(name => name[0].toLocaleUpperCase()) diff --git a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html new file mode 100644 index 0000000000..d3bdf6b6ae --- /dev/null +++ b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html @@ -0,0 +1,13 @@ +

+
+ {{ tile.graphic.matIcon }} + + + +
+
+

{{ tile.label }}

+
+
{{ tile.description }}
+
diff --git a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.scss b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.scss new file mode 100644 index 0000000000..68db7e8382 --- /dev/null +++ b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.scss @@ -0,0 +1,74 @@ +.tile-selector { + $tile-height: 200px; + border-radius: 3px; + cursor: pointer; + display: flex; + flex-direction: column; + height: $tile-height; + opacity: .5; + transition: transform .2s ease; + user-select: none; + width: 100%; + + &__taller { + height: 260px; + } + &:hover { + opacity: 1; + transform: scale(1.02); + } + &__more { + align-items: center; + cursor: pointer; + display: flex; + font-size: 16px; + height: $tile-height; + justify-content: center; + } + + &:active { + transform: scale(.98); + } + + &__active { + opacity: 1; + } + + &__header { + align-items: center; + display: flex; + flex: 2; + justify-content: center; + width: 100%; + + img { + height: 100px; + } + } + + &__description { + flex: 0; + padding: 10px; + text-align: center; + } + + &__content { + display: flex; + flex: 0; + flex-direction: column; + justify-content: center; + opacity: .8; + padding: 0 1em; + position: relative; + text-align: center; + word-wrap: break-word; + } + + $icon-size: 80px; + &__icon { + font-size: $icon-size; + height: $icon-size; + opacity: .6; + width: $icon-size; + } +} diff --git a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.spec.ts b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.spec.ts new file mode 100644 index 0000000000..3e1340d7b2 --- /dev/null +++ b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TileSelectorTileComponent } from './tile-selector-tile.component'; + +describe('TileSelectorTileComponent', () => { + let component: TileSelectorTileComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TileSelectorTileComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TileSelectorTileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.theme.scss b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.theme.scss similarity index 100% rename from src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.theme.scss rename to src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.theme.scss diff --git a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.ts b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.ts new file mode 100644 index 0000000000..80a692e5cb --- /dev/null +++ b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.ts @@ -0,0 +1,21 @@ +import { Component, Input, EventEmitter, Output } from '@angular/core'; +import { ITileConfig } from '../tile/tile-selector.types'; + +@Component({ + selector: 'app-tile-selector-tile', + templateUrl: './tile-selector-tile.component.html', + styleUrls: ['./tile-selector-tile.component.scss'] +}) +export class TileSelectorTileComponent { + + @Input() tile: ITileConfig; + + @Input() active: boolean; + + @Output() tileSelect = new EventEmitter(); + + public onClick(tile: ITileConfig) { + this.tileSelect.emit(tile); + } + +} diff --git a/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.html b/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.html index 2afc52b34b..b3b0112dae 100644 --- a/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.html +++ b/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.html @@ -11,18 +11,7 @@
-
-
- {{ tile.graphic.matIcon }} - - - -
-
-

{{ tile.label }}

-
-
+ +
\ No newline at end of file diff --git a/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.scss b/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.scss index a45342aa65..c5a5ce6951 100644 --- a/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.scss +++ b/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.scss @@ -23,69 +23,3 @@ grid-template-columns: repeat(5, 1fr); } } - -.tile-selector { - $tile-height: 200px; - border-radius: 3px; - cursor: pointer; - display: flex; - flex-direction: column; - height: $tile-height; - opacity: .5; - transition: transform .2s ease; - user-select: none; - width: 100%; - &:hover { - opacity: 1; - transform: scale(1.02); - } - &__more { - align-items: center; - cursor: pointer; - display: flex; - font-size: 16px; - height: $tile-height; - justify-content: center; - } - - &:active { - transform: scale(.98); - } - - &__selected, - &__active { - opacity: 1; - } - - &__header { - align-items: center; - display: flex; - flex: 2; - justify-content: center; - width: 100%; - - img { - height: 100px; - } - } - - &__content { - display: flex; - flex: 1; - flex-direction: column; - justify-content: center; - opacity: .8; - padding: 0 1em; - position: relative; - text-align: center; - word-wrap: break-word; - } - - $icon-size: 80px; - &__icon { - font-size: $icon-size; - height: $icon-size; - opacity: .6; - width: $icon-size; - } -} diff --git a/src/frontend/packages/core/src/shared/components/tile/tile-selector.types.ts b/src/frontend/packages/core/src/shared/components/tile/tile-selector.types.ts index 23cf92df99..9402a43901 100644 --- a/src/frontend/packages/core/src/shared/components/tile/tile-selector.types.ts +++ b/src/frontend/packages/core/src/shared/components/tile/tile-selector.types.ts @@ -14,7 +14,8 @@ export class ITileConfig { public label: string | number, public graphic: ITileGraphic, public data?: T, - public hidden = false + public hidden = false, + public description = '' ) { } } diff --git a/src/frontend/packages/core/src/shared/shared.module.ts b/src/frontend/packages/core/src/shared/shared.module.ts index 12aae65f83..4f7c8c0e25 100644 --- a/src/frontend/packages/core/src/shared/shared.module.ts +++ b/src/frontend/packages/core/src/shared/shared.module.ts @@ -116,6 +116,7 @@ import { SimpleListComponent } from './components/list/simple-list/simple-list.c import { ListHostDirective } from './components/list/simple-list/list-host.directive'; import { EndpointListHelper } from './components/list/list-types/endpoint/endpoint-list.helpers'; import { EndpointsListConfigService } from './components/list/list-types/endpoint/endpoints-list-config.service'; +import { TileSelectorTileComponent } from './components/tile-selector-tile/tile-selector-tile.component'; /* tslint:disable:max-line-length */ @@ -218,6 +219,7 @@ import { EndpointsListConfigService } from './components/list/list-types/endpoin UnlimitedInputComponent, SimpleListComponent, ListHostDirective, + TileSelectorTileComponent, ], exports: [ ApplicationStateIconPipe, @@ -306,7 +308,8 @@ import { EndpointsListConfigService } from './components/list/list-types/endpoin PollingIndicatorComponent, UnlimitedInputComponent, SimpleListComponent, - ListHostDirective + ListHostDirective, + TileSelectorTileComponent, ], entryComponents: [ DialogConfirmComponent, diff --git a/src/frontend/packages/store/src/actions/setup.actions.ts b/src/frontend/packages/store/src/actions/setup.actions.ts index 2bd72603a3..97aba33aef 100644 --- a/src/frontend/packages/store/src/actions/setup.actions.ts +++ b/src/frontend/packages/store/src/actions/setup.actions.ts @@ -1,5 +1,5 @@ import { Action } from '@ngrx/store'; -import { UaaSetupData } from '../types/uaa-setup.types'; +import { UaaSetupData, LocalAdminSetupData } from '../types/uaa-setup.types'; export const SETUP_UAA = '[Setup] Setup UAA'; export const SETUP_UAA_SAVE = '[Setup] Setup UAA save'; @@ -8,7 +8,7 @@ export const SETUP_UAA_FAILED = '[Setup] Setup UAA failed'; export class SetupUAA implements Action { constructor( - public setupData: UaaSetupData + public setupData: UaaSetupData | LocalAdminSetupData ) { } type = SETUP_UAA; } diff --git a/src/frontend/packages/store/src/effects/uaa-setup.effects.ts b/src/frontend/packages/store/src/effects/uaa-setup.effects.ts index 5e425431e3..33bfb3ce72 100644 --- a/src/frontend/packages/store/src/effects/uaa-setup.effects.ts +++ b/src/frontend/packages/store/src/effects/uaa-setup.effects.ts @@ -1,4 +1,6 @@ +import { UaaSetupData, LocalAdminSetupData } from './../types/uaa-setup.types'; import { Injectable } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { catchError, map, switchMap } from 'rxjs/operators'; @@ -10,7 +12,6 @@ import { SETUP_UAA_SAVE, SetupUAASave, } from './../actions/setup.actions'; -import { HttpClient } from '@angular/common/http'; @Injectable() @@ -22,47 +23,28 @@ export class UAASetupEffect { ) { } baseUrl = '/pp/v1/setup'; + uaaSetupUrl = '/pp/v1/setup/check'; @Effect() uaaSetupRequest$ = this.actions$.pipe( ofType(SETUP_UAA), switchMap(({ setupData }) => { - const params = { - console_client: setupData.console_client, - username: setupData.username, - password: setupData.password, - skip_ssl_validation: setupData.skip_ssl_validation.toString() || 'false', - uaa_endpoint: setupData.uaa_endpoint, - use_sso: setupData.use_sso.toString() || 'false', - console_client_secret: setupData.console_client_secret, - }; - return this.http.post(`${this.baseUrl}/check`, null, { - headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, - params + const params = this.getParams(setupData); + return this.http.post(this.uaaSetupUrl, params, { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }).pipe( map(data => new SetupUAASuccess(data)), - catchError((err, caught) => [new SetupUAAFailed(`Failed to setup UAA endpoint. ${this.fetchError(err)}`)]) + catchError((err, caught) => [new SetupUAAFailed(`Failed to save UAA configuration. ${this.fetchError(err)}`)]) ); })); - - @Effect() uassSetScope = this.actions$.pipe( + @Effect() uaaSetupSetScope = this.actions$.pipe( ofType(SETUP_UAA_SAVE), switchMap(({ setupData }) => { - const params = { - console_client: setupData.console_client, - username: setupData.username, - password: setupData.password, - skip_ssl_validation: setupData.skip_ssl_validation.toString() || 'false', - uaa_endpoint: setupData.uaa_endpoint, - use_sso: setupData.use_sso.toString() || 'false', - console_admin_scope: setupData.console_admin_scope, - - }; - return this.http.post(this.baseUrl, null, { - params, - headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, + const params = this.getParams(setupData); + return this.http.post(this.baseUrl, params, { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }).pipe( - map(data => new SetupUAASuccess({})), + map(data => new SetupUAASuccess(data)), catchError((err, caught) => [new SetupUAAFailed(`Failed to setup Administrator scope. ${this.fetchError(err)}`)]) ); })); @@ -74,4 +56,27 @@ export class UAASetupEffect { } catch (err) { } return ''; } + private getParams(setupData: any): HttpParams { + let params = new HttpParams(); + if ((setupData as UaaSetupData).console_client) { + const uaaSetupData = setupData as UaaSetupData; + params = params + .set('console_client', uaaSetupData.console_client) + .set('username', uaaSetupData.username) + .set('password', uaaSetupData.password) + .set('skip_ssl_validation', uaaSetupData.skip_ssl_validation.toString() || 'false') + .set('uaa_endpoint', uaaSetupData.uaa_endpoint) + .set('use_sso', uaaSetupData.use_sso.toString() || 'false'); + if (uaaSetupData.console_client_secret) { + params = params.append('console_client_secret', uaaSetupData.console_client_secret); + } + if (uaaSetupData.console_admin_scope) { + params = params.set('console_admin_scope', uaaSetupData.console_admin_scope); + } + } else { + const localSetupData = setupData as LocalAdminSetupData; + params = params.set('local_admin_password', localSetupData.local_admin_password); + } + return params; + } } diff --git a/src/frontend/packages/store/src/types/uaa-setup.types.ts b/src/frontend/packages/store/src/types/uaa-setup.types.ts index 3f5b756ef4..a74daef1e4 100644 --- a/src/frontend/packages/store/src/types/uaa-setup.types.ts +++ b/src/frontend/packages/store/src/types/uaa-setup.types.ts @@ -21,3 +21,7 @@ export interface UaaSetupData { use_sso: boolean; console_admin_scope?: string; } + +export interface LocalAdminSetupData { + local_admin_password: string; +} diff --git a/src/jetstream/auth.go b/src/jetstream/auth.go index 70881b43ad..7de23ba3e0 100644 --- a/src/jetstream/auth.go +++ b/src/jetstream/auth.go @@ -78,3 +78,11 @@ func (p *portalProxy) login(c echo.Context, skipSSLValidation bool, client strin return uaaRes, u, nil } + +func (p *portalProxy) consoleLogin(c echo.Context) error { + return p.StratosAuthService.Login(c) +} + +func (p *portalProxy) consoleLogout(c echo.Context) error { + return p.StratosAuthService.Logout(c) +} diff --git a/src/jetstream/default.config.properties b/src/jetstream/default.config.properties index 8d6a68ddc0..a9a272543b 100644 --- a/src/jetstream/default.config.properties +++ b/src/jetstream/default.config.properties @@ -7,7 +7,7 @@ SKIP_SSL_VALIDATION=true CONSOLE_PROXY_TLS_ADDRESS=:5443 CONSOLE_CLIENT=console CF_CLIENT=cf -UAA_ENDPOINT=http://localhost:8080 +#UAA_ENDPOINT=http://localhost:8080 CONSOLE_ADMIN_SCOPE=stratos.admin CF_ADMIN_ROLE=cloud_controller.admin ALLOWED_ORIGINS=http://nginx @@ -37,10 +37,10 @@ INVITE_USER_CLIENT_ID= INVITE_USER_CLIENT_SECRET= # Use local admin user rather than UAA users -# AUTH_ENDPOINT_TYPE=local -# LOCAL_USER=localuser -# LOCAL_USER_PASSWORD=localuserpass -# LOCAL_USER_SCOPE=stratos.admin +#AUTH_ENDPOINT_TYPE=local +#LOCAL_USER=localuser +#LOCAL_USER_PASSWORD=localuserpass +#LOCAL_USER_SCOPE=stratos.admin # MariaDB database for local dev # DATABASE_PROVIDER=mysql diff --git a/src/jetstream/main.go b/src/jetstream/main.go index 51772e4ce6..aff32c8ad5 100644 --- a/src/jetstream/main.go +++ b/src/jetstream/main.go @@ -253,6 +253,16 @@ func main() { return } + // Init auth service + err = portalProxy.InitStratosAuthService(interfaces.AuthEndpointTypes[portalProxy.Config.AuthEndpointType]) + if err != nil { + log.Warnf("Defaulting to UAA authentication: %v", err) + err = portalProxy.InitStratosAuthService(interfaces.Remote) + if err != nil { + log.Fatalf("Could not initialise auth service. %v", err) + } + } + // Initialise Plugins portalProxy.loadPlugins() @@ -340,6 +350,7 @@ func initialiseConsoleConfiguration(portalProxy *portalProxy) error { if consoleConfig.IsSetupComplete() { portalProxy.Config.ConsoleConfig = consoleConfig portalProxy.Config.SSOLogin = consoleConfig.UseSSO + portalProxy.Config.AuthEndpointType = consoleConfig.AuthEndpointType } return nil @@ -614,15 +625,6 @@ func newPortalProxy(pc interfaces.PortalConfig, dcp *sql.DB, ss HttpSessionStore UserInfo: pp.GetCNSIUserFromBasicToken, }) - err := pp.InitStratosAuthService(interfaces.AuthEndpointTypes[pp.Config.AuthEndpointType]) - if err != nil { - log.Warnf("Defaulting to UAA authentication: %v", err) - err = pp.InitStratosAuthService(interfaces.Remote) - if err != nil { - log.Fatalf("Could not initialise auth service. %v", err) - } - } - // OIDC pp.AddAuthProvider(interfaces.AuthTypeOIDC, interfaces.AuthProvider{ Handler: pp.doOidcFlowRequest, @@ -798,13 +800,13 @@ func (p *portalProxy) registerRoutes(e *echo.Echo, needSetupMiddleware bool) { // Add middleware to block requests if unconfigured if needSetupMiddleware { e.Use(p.SetupMiddleware()) - pp.POST("/v1/setup", p.setupConsole) - pp.POST("/v1/setup/check", p.setupConsoleCheck) + pp.POST("/v1/setup", p.saveConsoleSetupData) + pp.POST("/v1/setup/check", p.saveConsoleSetupDataUAA) } loginAuthGroup := pp.Group("/v1/auth") - loginAuthGroup.POST("/login/uaa", p.StratosAuthService.Login) - loginAuthGroup.POST("/logout", p.StratosAuthService.Logout) + loginAuthGroup.POST("/login/uaa", p.consoleLogin) + loginAuthGroup.POST("/logout", p.consoleLogout) // SSO Routes will only respond if SSO is enabled loginAuthGroup.GET("/sso_login", p.initSSOlogin) diff --git a/src/jetstream/setup_console.go b/src/jetstream/setup_console.go index 9a67fff3e3..b36a703972 100644 --- a/src/jetstream/setup_console.go +++ b/src/jetstream/setup_console.go @@ -31,6 +31,15 @@ const ( func parseConsoleConfigFromForm(c echo.Context) (*interfaces.ConsoleConfig, error) { consoleConfig := new(interfaces.ConsoleConfig) + + // Local admin user configuration? + password := c.FormValue("local_admin_password") + if len(password) > 0 { + consoleConfig.LocalUserPassword = password + consoleConfig.AuthEndpointType = "local" + return consoleConfig, nil + } + url, err := url.Parse(c.FormValue("uaa_endpoint")) if err != nil { return nil, echo.NewHTTPError(http.StatusBadRequest, "Invalid UAA Endpoint value") @@ -60,7 +69,7 @@ func parseConsoleConfigFromForm(c echo.Context) (*interfaces.ConsoleConfig, erro // Check the initial parameter set and fetch the list of available scopes // This does not persist the configuration to the database at this stage -func (p *portalProxy) setupConsoleCheck(c echo.Context) error { +func (p *portalProxy) saveConsoleSetupDataUAA(c echo.Context) error { // Check if already set up if p.GetConfig().ConsoleConfig.IsSetupComplete() { @@ -113,6 +122,42 @@ func (p *portalProxy) setupConsoleCheck(c echo.Context) error { } func saveConsoleConfig(consoleRepo console_config.Repository, consoleConfig *interfaces.ConsoleConfig) error { + + if interfaces.AuthEndpointTypes[consoleConfig.AuthEndpointType] == interfaces.Local { + return saveLocalUserConsoleConfig(consoleRepo, consoleConfig) + } + + return saveUAAConsoleConfig(consoleRepo, consoleConfig) +} + +func saveLocalUserConsoleConfig(consoleRepo console_config.Repository, consoleConfig *interfaces.ConsoleConfig) error { + + log.Info("saveLocalUserConsoleConfig") + + if err := consoleRepo.SetValue(systemGroupName, "AUTH_ENDPOINT_TYPE", "local"); err != nil { + return err + } + + if err := consoleRepo.SetValue(systemGroupName, "CONSOLE_ADMIN_SCOPE", "stratos.admin"); err != nil { + return err + } + + if err := consoleRepo.SetValue(systemGroupName, "LOCAL_USER", "admin"); err != nil { + return err + } + + if err := consoleRepo.SetValue(systemGroupName, "LOCAL_USER_SCOPE", "stratos.admin"); err != nil { + return err + } + + if err := consoleRepo.SetValue(systemGroupName, "LOCAL_USER_PASSWORD", consoleConfig.LocalUserPassword); err != nil { + return err + } + + return nil +} + +func saveUAAConsoleConfig(consoleRepo console_config.Repository, consoleConfig *interfaces.ConsoleConfig) error { log.Debugf("Saving ConsoleConfig: %+v", consoleConfig) if err := consoleRepo.SetValue(systemGroupName, "UAA_ENDPOINT", consoleConfig.UAAEndpoint.String()); err != nil { @@ -147,7 +192,7 @@ func saveConsoleConfig(consoleRepo console_config.Repository, consoleConfig *int } // Save the console setup -func (p *portalProxy) setupConsole(c echo.Context) error { +func (p *portalProxy) saveConsoleSetupData(c echo.Context) error { consoleRepo, err := console_config.NewPostgresConsoleConfigRepository(p.DatabaseConnectionPool) if err != nil { @@ -344,6 +389,8 @@ func checkSetupComplete(portalProxy *portalProxy) bool { showStratosConfig(consoleConfig) portalProxy.Config.ConsoleConfig = consoleConfig portalProxy.Config.SSOLogin = consoleConfig.UseSSO + portalProxy.Config.AuthEndpointType = consoleConfig.AuthEndpointType + portalProxy.InitStratosAuthService(interfaces.AuthEndpointTypes[consoleConfig.AuthEndpointType]) } return consoleConfig.IsSetupComplete() From bfa3baca1352e09f8202c5a372c7e7d94393040b Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Mon, 2 Dec 2019 11:33:21 +0000 Subject: [PATCH 02/10] Fix type issuw with production build --- .../tile-selector-tile/tile-selector-tile.component.ts | 6 +++--- .../core/src/shared/components/tile/tile-selector.types.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.ts b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.ts index 80a692e5cb..f4f6a69ec7 100644 --- a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.ts +++ b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.ts @@ -1,14 +1,14 @@ import { Component, Input, EventEmitter, Output } from '@angular/core'; -import { ITileConfig } from '../tile/tile-selector.types'; +import { ITileConfig, ITileIconConfig, ITileImgConfig, ITileData } from '../tile/tile-selector.types'; @Component({ selector: 'app-tile-selector-tile', templateUrl: './tile-selector-tile.component.html', styleUrls: ['./tile-selector-tile.component.scss'] }) -export class TileSelectorTileComponent { +export class TileSelectorTileComponent { - @Input() tile: ITileConfig; + @Input() tile: ITileConfig; @Input() active: boolean; diff --git a/src/frontend/packages/core/src/shared/components/tile/tile-selector.types.ts b/src/frontend/packages/core/src/shared/components/tile/tile-selector.types.ts index 9402a43901..d443c03fcb 100644 --- a/src/frontend/packages/core/src/shared/components/tile/tile-selector.types.ts +++ b/src/frontend/packages/core/src/shared/components/tile/tile-selector.types.ts @@ -9,10 +9,10 @@ export interface ITileImgConfig { export type ITileGraphic = ITileIconConfig | ITileImgConfig; -export class ITileConfig { +export class ITileConfig { constructor( public label: string | number, - public graphic: ITileGraphic, + public graphic: Y, public data?: T, public hidden = false, public description = '' From bef8c1f6480330485258928c80f958302b5e186c Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Mon, 2 Dec 2019 13:38:50 +0000 Subject: [PATCH 03/10] Fix front end unit tests --- .../tile-selector-tile.component.html | 2 +- .../tile-selector-tile.component.spec.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html index d3bdf6b6ae..301821bdac 100644 --- a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html +++ b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html @@ -9,5 +9,5 @@

{{ tile.label }}

-
{{ tile.description }}
+
{{ tile.description }}
diff --git a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.spec.ts b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.spec.ts index 3e1340d7b2..4032667bb6 100644 --- a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.spec.ts +++ b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.spec.ts @@ -1,20 +1,25 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { TileSelectorTileComponent } from './tile-selector-tile.component'; +import { ITileImgConfig } from '../tile/tile-selector.types'; +import { MDAppModule } from '../../../core/md.module'; describe('TileSelectorTileComponent', () => { - let component: TileSelectorTileComponent; - let fixture: ComponentFixture; + let component: TileSelectorTileComponent; + let fixture: ComponentFixture>; beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [ + MDAppModule + ], declarations: [ TileSelectorTileComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(TileSelectorTileComponent); + fixture = TestBed.createComponent(TileSelectorTileComponent) as ComponentFixture>; component = fixture.componentInstance; fixture.detectChanges(); }); From 1f7be004bb6dbcadad27fc3ceccc1c0d8b63b016 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Mon, 2 Dec 2019 13:57:52 +0000 Subject: [PATCH 04/10] Fix backend tests --- build/bk-build.sh | 2 +- src/jetstream/auth_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/build/bk-build.sh b/build/bk-build.sh index 2dda25542f..9e55c68286 100755 --- a/build/bk-build.sh +++ b/build/bk-build.sh @@ -36,7 +36,7 @@ if [ "${ACTION}" == "build" ]; then echo "Build complete ..." else echo "Running backend tests ..." - GO111MODULE=on go test ./... -v + GO111MODULE=on go test ./... -v -count=1 fi popd > /dev/null diff --git a/src/jetstream/auth_test.go b/src/jetstream/auth_test.go index 0b3d183154..b7657fbede 100644 --- a/src/jetstream/auth_test.go +++ b/src/jetstream/auth_test.go @@ -742,6 +742,10 @@ func TestVerifySession(t *testing.T) { res, _, ctx, pp, db, mock := setupHTTPTest(req) defer db.Close() + if e := pp.InitStratosAuthService(interfaces.Remote); e != nil { + log.Fatalf("Could not initialise auth service: %v", e) + } + // Set a dummy userid in session - normally the login to UAA would do this. sessionValues := make(map[string]interface{}) sessionValues["user_id"] = mockUserGUID @@ -850,6 +854,10 @@ func TestVerifySessionExpired(t *testing.T) { _, _, ctx, pp, db, mock := setupHTTPTest(req) defer db.Close() + if e := pp.InitStratosAuthService(interfaces.Remote); e != nil { + log.Fatalf("Could not initialise auth service: %v", e) + } + // Set a dummy userid in session - normally the login to UAA would do this. sessionValues := make(map[string]interface{}) sessionValues["user_id"] = mockUserGUID From 3f64c0cf98e95437091f6d045fe11681547f0cc6 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Fri, 13 Dec 2019 15:56:42 +0000 Subject: [PATCH 05/10] Address PR review --- .../local-account-wizard.component.html | 18 ++++----- .../local-account-wizard.component.scss | 2 +- .../local-account-wizard.component.ts | 27 +++++-------- .../setup-welcome.component.html | 2 +- .../setup-welcome.component.scss | 9 ++++- .../console-uaa-wizard.component.ts | 8 ++-- .../stepper/steppers/steppers.component.scss | 1 + .../store/src/actions/setup.actions.ts | 24 +++++------ .../store/src/effects/uaa-setup.effects.ts | 40 ++++++++++--------- .../store/src/reducers/uaa-setup.reducers.ts | 12 +++--- src/jetstream/default.config.properties | 10 ++--- src/jetstream/main.go | 4 +- src/jetstream/setup_console.go | 12 +++--- 13 files changed, 86 insertions(+), 83 deletions(-) diff --git a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.html b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.html index e70dad051a..e00eb19326 100644 --- a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.html +++ b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.html @@ -3,23 +3,23 @@

Stratos Setup with Local Admin Account

-
+
- + -
-

+

+

Please choose a password to use for the local Administrator account.

-

This will configure Stratos with a single, built-in account with the username admin +

This will configure Stratos with a single, built-in account with the username admin and the password that you choose below.

-
-
+ +
- + - +
diff --git a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.scss b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.scss index 8ee24f82e9..f3bf41d71b 100644 --- a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.scss +++ b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.scss @@ -4,7 +4,7 @@ height: 100%; } -.uaa-wizard { +.local-setup-wizard { display: flex; flex: 1; margin: 0 100px; diff --git a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.ts b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.ts index 8574fd2020..51f812ac42 100644 --- a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.ts +++ b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.ts @@ -4,11 +4,11 @@ import { Observable, BehaviorSubject, of as obsof } from 'rxjs'; import { StepOnNextFunction } from '../../../shared/components/stepper/step/step.component'; import { Store } from '@ngrx/store'; import { InternalAppState } from '../../../../../store/src/app-state'; -import { SetupUAASave } from '../../../../../store/src/actions/setup.actions'; -import { filter, delay, take, map } from 'rxjs/operators'; +import { filter, delay, take, map, tap } from 'rxjs/operators'; import { UAASetupState, LocalAdminSetupData } from '../../../../../store/src/types/uaa-setup.types'; import { AuthState } from '../../../../../store/src/reducers/auth.reducer'; import { VerifySession } from '../../../../../store/src/actions/auth.actions'; +import { SetupSaveConfig } from '../../../../../store/src/actions/setup.actions'; @Component({ selector: 'app-local-account-wizard', @@ -18,7 +18,7 @@ import { VerifySession } from '../../../../../store/src/actions/auth.actions'; export class LocalAccountWizardComponent implements OnInit { passwordForm: FormGroup; - validateUAAForm: Observable; + validateLocalAuthForm: Observable; applyingSetup$ = new BehaviorSubject(false); constructor(private store: Store>) { } @@ -29,31 +29,26 @@ export class LocalAccountWizardComponent implements OnInit { adminPasswordConfirm: new FormControl('', [Validators.required as any]) }); - let observer; - this.validateUAAForm = new Observable(o => { - observer = o; - observer.next(false); - }); - - this.passwordForm.valueChanges.subscribe(() => { - observer.next(this.passwordForm.valid); - this.passwordForm.controls.adminPasswordConfirm.setValidators([Validators.required, this.confirmPasswordValidator()]); - }); + this.validateLocalAuthForm = this.passwordForm.valueChanges.pipe( + tap(() => { + this.passwordForm.controls.adminPasswordConfirm.setValidators([Validators.required, this.confirmPasswordValidator()]); + }), + map(() => this.passwordForm.valid) + ); } next: StepOnNextFunction = () => { - const data: LocalAdminSetupData = { local_admin_password: this.passwordForm.get('adminPassword').value, }; this.applyingSetup$.next(true); - this.store.dispatch(new SetupUAASave(data)); + this.store.dispatch(new SetupSaveConfig(data)); return this.store.select(s => [s.uaaSetup, s.auth]).pipe( filter(([uaa, auth]: [UAASetupState, AuthState]) => { return !(uaa.settingUp || auth.verifying); }), - delay(3000), + delay(2000), take(10), filter(([uaa, auth]: [UAASetupState, AuthState]) => { const validUAASessionData = auth.sessionData && !auth.sessionData.uaaError; diff --git a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.html b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.html index 24f403ddfc..d3079fc263 100644 --- a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.html +++ b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.html @@ -10,7 +10,7 @@

Stratos Setup

Welcome to Stratos

-

Before you can login, you need to choose how users will login to Stratos and complete the required configuration for the chosen method of authenticaion:

+

Before you can login, you need to choose how users will login to Stratos and complete the required configuration for the chosen method of authentication:

diff --git a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.scss b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.scss index 65961dffca..d029724603 100644 --- a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.scss +++ b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.scss @@ -34,12 +34,17 @@ &__intro { font-size: 28px; font-weight: 600; - padding-bottom: 26px; + padding-bottom: 20px; + text-align: center; + } + + &__welcome { + line-height: 1.5em; text-align: center; } &__config { - margin-bottom: 40px; + margin-bottom: 30px; padding: 10px; } diff --git a/src/frontend/packages/core/src/features/setup/uaa-wizard/console-uaa-wizard.component.ts b/src/frontend/packages/core/src/features/setup/uaa-wizard/console-uaa-wizard.component.ts index e0fd8f64c0..a707550488 100644 --- a/src/frontend/packages/core/src/features/setup/uaa-wizard/console-uaa-wizard.component.ts +++ b/src/frontend/packages/core/src/features/setup/uaa-wizard/console-uaa-wizard.component.ts @@ -6,11 +6,11 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { delay, filter, map, skipWhile, take } from 'rxjs/operators'; import { VerifySession } from '../../../../../store/src/actions/auth.actions'; -import { SetupUAA, SetupUAASave } from '../../../../../store/src/actions/setup.actions'; import { InternalAppState } from '../../../../../store/src/app-state'; import { AuthState } from '../../../../../store/src/reducers/auth.reducer'; import { UAASetupState } from '../../../../../store/src/types/uaa-setup.types'; import { StepOnNextFunction } from '../../../shared/components/stepper/step/step.component'; +import { SetupConsoleGetScopes, SetupSaveConfig } from '../../../../../store/src/actions/setup.actions'; @Component({ selector: 'app-console-uaa-wizard', @@ -35,7 +35,7 @@ export class ConsoleUaaWizardComponent implements OnInit { applyingSetup$ = new BehaviorSubject(false); uaaFormNext: StepOnNextFunction = () => { - this.store.dispatch(new SetupUAA({ + this.store.dispatch(new SetupConsoleGetScopes({ uaa_endpoint: this.uaaForm.get('apiUrl').value, console_client: this.uaaForm.get('clientId').value, password: this.uaaForm.get('adminPassword').value, @@ -67,7 +67,7 @@ export class ConsoleUaaWizardComponent implements OnInit { } uaaScopeNext: StepOnNextFunction = () => { - this.store.dispatch(new SetupUAASave({ + this.store.dispatch(new SetupSaveConfig({ uaa_endpoint: this.uaaForm.get('apiUrl').value, console_client: this.uaaForm.get('clientId').value, password: this.uaaForm.get('adminPassword').value, @@ -83,7 +83,7 @@ export class ConsoleUaaWizardComponent implements OnInit { filter(([uaa, auth]: [UAASetupState, AuthState]) => { return !(uaa.settingUp || auth.verifying); }), - delay(3000), + delay(2000), take(10), filter(([uaa, auth]: [UAASetupState, AuthState]) => { const validUAASessionData = auth.sessionData && !auth.sessionData.uaaError; diff --git a/src/frontend/packages/core/src/shared/components/stepper/steppers/steppers.component.scss b/src/frontend/packages/core/src/shared/components/stepper/steppers/steppers.component.scss index c899e137ca..45282e2dc8 100644 --- a/src/frontend/packages/core/src/shared/components/stepper/steppers/steppers.component.scss +++ b/src/frontend/packages/core/src/shared/components/stepper/steppers/steppers.component.scss @@ -67,6 +67,7 @@ } &__wrapper { display: flex; + flex: 1; min-height: 100%; } &__navigation { diff --git a/src/frontend/packages/store/src/actions/setup.actions.ts b/src/frontend/packages/store/src/actions/setup.actions.ts index 97aba33aef..b23249f98a 100644 --- a/src/frontend/packages/store/src/actions/setup.actions.ts +++ b/src/frontend/packages/store/src/actions/setup.actions.ts @@ -1,29 +1,29 @@ import { Action } from '@ngrx/store'; import { UaaSetupData, LocalAdminSetupData } from '../types/uaa-setup.types'; -export const SETUP_UAA = '[Setup] Setup UAA'; -export const SETUP_UAA_SAVE = '[Setup] Setup UAA save'; -export const SETUP_UAA_SUCCESS = '[Setup] Setup UAA success'; -export const SETUP_UAA_FAILED = '[Setup] Setup UAA failed'; +export const SETUP_GET_SCOPES = '[Setup] Setup get scopes'; +export const SETUP_SAVE_CONFIG = '[Setup] Setup save'; +export const SETUP_SUCCESS = '[Setup] Setup success'; +export const SETUP_FAILED = '[Setup] Setup failed'; -export class SetupUAA implements Action { +export class SetupConsoleGetScopes implements Action { constructor( public setupData: UaaSetupData | LocalAdminSetupData ) { } - type = SETUP_UAA; + type = SETUP_GET_SCOPES; } -export class SetupUAASave extends SetupUAA { - type = SETUP_UAA_SAVE; +export class SetupSaveConfig extends SetupConsoleGetScopes { + type = SETUP_SAVE_CONFIG; } -export class SetupUAASuccess implements Action { +export class SetupSuccess implements Action { constructor(public payload: {}) { } - type = SETUP_UAA_SUCCESS; + type = SETUP_SUCCESS; } -export class SetupUAAFailed implements Action { +export class SetupFailed implements Action { constructor(public message: string) { } - type = SETUP_UAA_FAILED; + type = SETUP_FAILED; } diff --git a/src/frontend/packages/store/src/effects/uaa-setup.effects.ts b/src/frontend/packages/store/src/effects/uaa-setup.effects.ts index 33bfb3ce72..c0908d89e6 100644 --- a/src/frontend/packages/store/src/effects/uaa-setup.effects.ts +++ b/src/frontend/packages/store/src/effects/uaa-setup.effects.ts @@ -5,12 +5,12 @@ import { Actions, Effect, ofType } from '@ngrx/effects'; import { catchError, map, switchMap } from 'rxjs/operators'; import { - SETUP_UAA, - SetupUAA, - SetupUAAFailed, - SetupUAASuccess, - SETUP_UAA_SAVE, - SetupUAASave, + SETUP_GET_SCOPES, + SETUP_SAVE_CONFIG, + SetupConsoleGetScopes, + SetupSuccess, + SetupFailed, + SetupSaveConfig, } from './../actions/setup.actions'; @@ -22,30 +22,30 @@ export class UAASetupEffect { private actions$: Actions ) { } - baseUrl = '/pp/v1/setup'; - uaaSetupUrl = '/pp/v1/setup/check'; + getSetupScopesUrl = '/pp/v1/setup.check'; + saveSetupUrl = '/pp/v1/setup/save'; - @Effect() uaaSetupRequest$ = this.actions$.pipe( - ofType(SETUP_UAA), + @Effect() setupGetScopes$ = this.actions$.pipe( + ofType(SETUP_GET_SCOPES), switchMap(({ setupData }) => { const params = this.getParams(setupData); - return this.http.post(this.uaaSetupUrl, params, { + return this.http.post(this.getSetupScopesUrl, params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }).pipe( - map(data => new SetupUAASuccess(data)), - catchError((err, caught) => [new SetupUAAFailed(`Failed to save UAA configuration. ${this.fetchError(err)}`)]) + map(data => new SetupSuccess(data)), + catchError((err, caught) => [new SetupFailed(`Failed to save configuration. ${this.fetchError(err)}`)]) ); })); - @Effect() uaaSetupSetScope = this.actions$.pipe( - ofType(SETUP_UAA_SAVE), + @Effect() setupSaveConfiguration$ = this.actions$.pipe( + ofType(SETUP_SAVE_CONFIG), switchMap(({ setupData }) => { const params = this.getParams(setupData); - return this.http.post(this.baseUrl, params, { + return this.http.post(this.saveSetupUrl, params, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }).pipe( - map(data => new SetupUAASuccess(data)), - catchError((err, caught) => [new SetupUAAFailed(`Failed to setup Administrator scope. ${this.fetchError(err)}`)]) + map(data => new SetupSuccess(data)), + catchError((err, caught) => [new SetupFailed(`Failed to setup Administrator scope. ${this.fetchError(err)}`)]) ); })); @@ -56,7 +56,9 @@ export class UAASetupEffect { } catch (err) { } return ''; } - private getParams(setupData: any): HttpParams { + + + private getParams(setupData: any): any { let params = new HttpParams(); if ((setupData as UaaSetupData).console_client) { const uaaSetupData = setupData as UaaSetupData; diff --git a/src/frontend/packages/store/src/reducers/uaa-setup.reducers.ts b/src/frontend/packages/store/src/reducers/uaa-setup.reducers.ts index 6ca565f7b8..eee73abbf8 100644 --- a/src/frontend/packages/store/src/reducers/uaa-setup.reducers.ts +++ b/src/frontend/packages/store/src/reducers/uaa-setup.reducers.ts @@ -1,6 +1,6 @@ -import { SETUP_UAA, SETUP_UAA_FAILED, SETUP_UAA_SAVE, SETUP_UAA_SUCCESS } from './../actions/setup.actions'; -import { Action } from '@ngrx/store'; +import { SETUP_SUCCESS } from './../actions/setup.actions'; import { UAASetupState } from '../types/uaa-setup.types'; +import { SETUP_GET_SCOPES, SETUP_SAVE_CONFIG, SETUP_FAILED } from '../actions/setup.actions'; const defaultState = { payload: null, @@ -12,8 +12,8 @@ const defaultState = { export function uaaSetupReducer(state: UAASetupState = defaultState, action) { switch (action.type) { - case SETUP_UAA_SAVE: - case SETUP_UAA: + case SETUP_GET_SCOPES: + case SETUP_SAVE_CONFIG: return { ...state, settingUp: true, @@ -21,7 +21,7 @@ export function uaaSetupReducer(state: UAASetupState = defaultState, action) { message: 'Setting up UAA', error: false }; - case SETUP_UAA_SUCCESS: + case SETUP_SUCCESS: return { ...state, settingUp: false, @@ -30,7 +30,7 @@ export function uaaSetupReducer(state: UAASetupState = defaultState, action) { error: false, payload: { ...state.payload, ...action.payload } }; - case SETUP_UAA_FAILED: + case SETUP_FAILED: return { ...state, settingUp: false, diff --git a/src/jetstream/default.config.properties b/src/jetstream/default.config.properties index a9a272543b..8d6a68ddc0 100644 --- a/src/jetstream/default.config.properties +++ b/src/jetstream/default.config.properties @@ -7,7 +7,7 @@ SKIP_SSL_VALIDATION=true CONSOLE_PROXY_TLS_ADDRESS=:5443 CONSOLE_CLIENT=console CF_CLIENT=cf -#UAA_ENDPOINT=http://localhost:8080 +UAA_ENDPOINT=http://localhost:8080 CONSOLE_ADMIN_SCOPE=stratos.admin CF_ADMIN_ROLE=cloud_controller.admin ALLOWED_ORIGINS=http://nginx @@ -37,10 +37,10 @@ INVITE_USER_CLIENT_ID= INVITE_USER_CLIENT_SECRET= # Use local admin user rather than UAA users -#AUTH_ENDPOINT_TYPE=local -#LOCAL_USER=localuser -#LOCAL_USER_PASSWORD=localuserpass -#LOCAL_USER_SCOPE=stratos.admin +# AUTH_ENDPOINT_TYPE=local +# LOCAL_USER=localuser +# LOCAL_USER_PASSWORD=localuserpass +# LOCAL_USER_SCOPE=stratos.admin # MariaDB database for local dev # DATABASE_PROVIDER=mysql diff --git a/src/jetstream/main.go b/src/jetstream/main.go index aff32c8ad5..df0edd6f8f 100644 --- a/src/jetstream/main.go +++ b/src/jetstream/main.go @@ -800,8 +800,8 @@ func (p *portalProxy) registerRoutes(e *echo.Echo, needSetupMiddleware bool) { // Add middleware to block requests if unconfigured if needSetupMiddleware { e.Use(p.SetupMiddleware()) - pp.POST("/v1/setup", p.saveConsoleSetupData) - pp.POST("/v1/setup/check", p.saveConsoleSetupDataUAA) + pp.POST("/v1/setup/check", p.setupGetAvailableScopes) + pp.POST("/v1/setup/save", p.setupSaveConfig) } loginAuthGroup := pp.Group("/v1/auth") diff --git a/src/jetstream/setup_console.go b/src/jetstream/setup_console.go index b36a703972..5d9234b0ec 100644 --- a/src/jetstream/setup_console.go +++ b/src/jetstream/setup_console.go @@ -22,7 +22,7 @@ import ( ) const ( - setupRequestRegex = "^/pp/v1/setup$" + setupRequestRegex = "^/pp/v1/setup/save$" setupCheckRequestRegex = "^/pp/v1/setup/check$" versionRequestRegex = "^/pp/v1/version$" backendRequestRegex = "^/pp/v1/" @@ -69,7 +69,7 @@ func parseConsoleConfigFromForm(c echo.Context) (*interfaces.ConsoleConfig, erro // Check the initial parameter set and fetch the list of available scopes // This does not persist the configuration to the database at this stage -func (p *portalProxy) saveConsoleSetupDataUAA(c echo.Context) error { +func (p *portalProxy) setupGetAvailableScopes(c echo.Context) error { // Check if already set up if p.GetConfig().ConsoleConfig.IsSetupComplete() { @@ -122,7 +122,6 @@ func (p *portalProxy) saveConsoleSetupDataUAA(c echo.Context) error { } func saveConsoleConfig(consoleRepo console_config.Repository, consoleConfig *interfaces.ConsoleConfig) error { - if interfaces.AuthEndpointTypes[consoleConfig.AuthEndpointType] == interfaces.Local { return saveLocalUserConsoleConfig(consoleRepo, consoleConfig) } @@ -191,8 +190,10 @@ func saveUAAConsoleConfig(consoleRepo console_config.Repository, consoleConfig * return nil } -// Save the console setup -func (p *portalProxy) saveConsoleSetupData(c echo.Context) error { +// Save the console setup data to the database +func (p *portalProxy) setupSaveConfig(c echo.Context) error { + + log.Warn("setupSaveConfig") consoleRepo, err := console_config.NewPostgresConsoleConfigRepository(p.DatabaseConnectionPool) if err != nil { @@ -218,7 +219,6 @@ func (p *portalProxy) saveConsoleSetupData(c echo.Context) error { } c.NoContent(http.StatusOK) - log.Infof("Updated Stratos setup") return nil } From 0f36fc99dbea7e3fa1b12e8afddcb158b91a09f9 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Mon, 6 Jan 2020 10:27:16 +0000 Subject: [PATCH 06/10] Fix logging levels --- src/jetstream/setup_console.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jetstream/setup_console.go b/src/jetstream/setup_console.go index 5d9234b0ec..f73df07729 100644 --- a/src/jetstream/setup_console.go +++ b/src/jetstream/setup_console.go @@ -131,7 +131,7 @@ func saveConsoleConfig(consoleRepo console_config.Repository, consoleConfig *int func saveLocalUserConsoleConfig(consoleRepo console_config.Repository, consoleConfig *interfaces.ConsoleConfig) error { - log.Info("saveLocalUserConsoleConfig") + log.Debug("saveLocalUserConsoleConfig") if err := consoleRepo.SetValue(systemGroupName, "AUTH_ENDPOINT_TYPE", "local"); err != nil { return err @@ -193,7 +193,7 @@ func saveUAAConsoleConfig(consoleRepo console_config.Repository, consoleConfig * // Save the console setup data to the database func (p *portalProxy) setupSaveConfig(c echo.Context) error { - log.Warn("setupSaveConfig") + log.Debug("setupSaveConfig") consoleRepo, err := console_config.NewPostgresConsoleConfigRepository(p.DatabaseConnectionPool) if err != nil { From f605c6e7d00c7c1c3f45d9b91cf15140f359e4d9 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Mon, 6 Jan 2020 19:44:59 +0000 Subject: [PATCH 07/10] FIx merge issue --- src/frontend/packages/core/src/shared/shared.module.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/frontend/packages/core/src/shared/shared.module.ts b/src/frontend/packages/core/src/shared/shared.module.ts index a1fbe09475..89c6f70805 100644 --- a/src/frontend/packages/core/src/shared/shared.module.ts +++ b/src/frontend/packages/core/src/shared/shared.module.ts @@ -117,10 +117,6 @@ import { CloudFoundryUserProvidedServicesService } from './services/cloud-foundr import { LongRunningOperationsService } from './services/long-running-op.service'; import { MetricsRangeSelectorService } from './services/metrics-range-selector.service'; import { UserPermissionDirective } from './user-permission.directive'; -import { SimpleListComponent } from './components/list/simple-list/simple-list.component'; -import { ListHostDirective } from './components/list/simple-list/list-host.directive'; -import { EndpointListHelper } from './components/list/list-types/endpoint/endpoint-list.helpers'; -import { EndpointsListConfigService } from './components/list/list-types/endpoint/endpoints-list-config.service'; import { TileSelectorTileComponent } from './components/tile-selector-tile/tile-selector-tile.component'; /* tslint:disable:max-line-length */ From 56089ed185d709cf961cae0581af8213e1861740 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Tue, 7 Jan 2020 11:59:05 +0000 Subject: [PATCH 08/10] Fix unit tests --- .../local-account-wizard.component.spec.ts | 24 ++++++++++++++++++- .../setup-welcome.component.spec.ts | 24 ++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.spec.ts b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.spec.ts index 21e620718a..bdc41a9533 100644 --- a/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.spec.ts +++ b/src/frontend/packages/core/src/features/setup/local-account-wizard/local-account-wizard.component.spec.ts @@ -1,6 +1,16 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { TabNavService } from '../../../../tab-nav.service'; +import { CoreModule } from '../../../core/core.module'; +import { MDAppModule } from '../../../core/md.module'; +import { PageHeaderModule } from '../../../shared/components/page-header/page-header.module'; +import { SharedModule } from '../../../shared/shared.module'; +import { SetupModule } from '../setup.module'; import { LocalAccountWizardComponent } from './local-account-wizard.component'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; +import { StoreModule } from '@ngrx/store'; describe('LocalAccountWizardComponent', () => { let component: LocalAccountWizardComponent; @@ -8,7 +18,19 @@ describe('LocalAccountWizardComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ LocalAccountWizardComponent ] + imports: [ + CoreModule, + SharedModule, + SetupModule, + RouterTestingModule, + FormsModule, + PageHeaderModule, + ReactiveFormsModule, + MDAppModule, + StoreModule.forRoot({}), + NoopAnimationsModule, + ], + providers: [TabNavService] }) .compileComponents(); })); diff --git a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.spec.ts b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.spec.ts index 2a0a506ac2..50db0d4bce 100644 --- a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.spec.ts +++ b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.spec.ts @@ -1,5 +1,15 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; +import { StoreModule } from '@ngrx/store'; +import { TabNavService } from '../../../../tab-nav.service'; +import { CoreModule } from '../../../core/core.module'; +import { MDAppModule } from '../../../core/md.module'; +import { PageHeaderModule } from '../../../shared/components/page-header/page-header.module'; +import { SharedModule } from '../../../shared/shared.module'; +import { SetupModule } from '../setup.module'; import { SetupWelcomeComponent } from './setup-welcome.component'; describe('SetupWelcomeComponent', () => { @@ -8,7 +18,19 @@ describe('SetupWelcomeComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ SetupWelcomeComponent ] + imports: [ + CoreModule, + SharedModule, + SetupModule, + RouterTestingModule, + FormsModule, + PageHeaderModule, + ReactiveFormsModule, + MDAppModule, + StoreModule.forRoot({}), + NoopAnimationsModule, + ], + providers: [TabNavService] }) .compileComponents(); })); From abc93ca91bbfef4dc45612ec19884305b9ab1d6e Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Tue, 7 Jan 2020 12:13:31 +0000 Subject: [PATCH 09/10] Fix setup via uaa and error handling - Fix background of error popup (ensure theme is initialised) - Fix setup via uaa (incorrect url) - Ensure error message in popup is shown (use new http error response object) --- .../setup-welcome/setup-welcome.component.ts | 9 ++--- .../core/src/features/setup/setup.module.ts | 18 +++++++--- .../store/src/effects/dashboard.effects.ts | 2 +- .../store/src/effects/uaa-setup.effects.ts | 35 +++++++++++-------- 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.ts b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.ts index a4d53a1f38..dece7a2108 100644 --- a/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.ts +++ b/src/frontend/packages/core/src/features/setup/setup-welcome/setup-welcome.component.ts @@ -1,9 +1,10 @@ import { Component } from '@angular/core'; -import { ITileConfig, ITileData } from '../../../shared/components/tile/tile-selector.types'; import { Store } from '@ngrx/store'; -import { GeneralEntityAppState } from '../../../../../store/src/app-state'; + import { RouterNav } from '../../../../../store/src/actions/router.actions'; +import { GeneralEntityAppState } from '../../../../../store/src/app-state'; import { BASE_REDIRECT_QUERY } from '../../../shared/components/stepper/stepper.types'; +import { ITileConfig, ITileData } from '../../../shared/components/tile/tile-selector.types'; @Component({ selector: 'app-setup-welcome', @@ -32,9 +33,9 @@ export class SetupWelcomeComponent { ]; - constructor(public store: Store) {} + constructor(private store: Store) { } - public selectionChange(tile: ITileConfig) { + public selectionChange(tile: ITileConfig) { if (tile) { this.store.dispatch(new RouterNav({ path: `setup/${tile.data.type}`, diff --git a/src/frontend/packages/core/src/features/setup/setup.module.ts b/src/frontend/packages/core/src/features/setup/setup.module.ts index 14e18ec1a7..cd9593967a 100644 --- a/src/frontend/packages/core/src/features/setup/setup.module.ts +++ b/src/frontend/packages/core/src/features/setup/setup.module.ts @@ -1,12 +1,13 @@ import { NgModule } from '@angular/core'; import { CoreModule } from '../../core/core.module'; +import { ThemeService } from '../../core/theme.service'; import { SharedModule } from '../../shared/shared.module'; -import { ConsoleUaaWizardComponent } from './uaa-wizard/console-uaa-wizard.component'; -import { UpgradePageComponent } from './upgrade-page/upgrade-page.component'; import { DomainMismatchComponent } from './domain-mismatch/domain-mismatch.component'; -import { SetupWelcomeComponent } from './setup-welcome/setup-welcome.component'; import { LocalAccountWizardComponent } from './local-account-wizard/local-account-wizard.component'; +import { SetupWelcomeComponent } from './setup-welcome/setup-welcome.component'; +import { ConsoleUaaWizardComponent } from './uaa-wizard/console-uaa-wizard.component'; +import { UpgradePageComponent } from './upgrade-page/upgrade-page.component'; @NgModule({ @@ -20,6 +21,15 @@ import { LocalAccountWizardComponent } from './local-account-wizard/local-accoun DomainMismatchComponent, SetupWelcomeComponent, LocalAccountWizardComponent + ], + providers: [ + ThemeService ] }) -export class SetupModule { } +export class SetupModule { + + constructor(themeService: ThemeService) { + // Initialise the theme service, this ensures things like popups are correctly styled + themeService.initialize(); + } +} diff --git a/src/frontend/packages/store/src/effects/dashboard.effects.ts b/src/frontend/packages/store/src/effects/dashboard.effects.ts index 0e796db044..2d34737508 100644 --- a/src/frontend/packages/store/src/effects/dashboard.effects.ts +++ b/src/frontend/packages/store/src/effects/dashboard.effects.ts @@ -17,7 +17,7 @@ export class DashboardEffect { @Effect({ dispatch: false }) hydrate$ = this.actions$.pipe( ofType(HYDRATE_DASHBOARD_STATE), map(() => { - // Ensure the previous theme is applied + // Ensure the previous theme is applied after dashboard is hydrated this.themeService.initialize(); }) ); diff --git a/src/frontend/packages/store/src/effects/uaa-setup.effects.ts b/src/frontend/packages/store/src/effects/uaa-setup.effects.ts index c0908d89e6..9e193e4380 100644 --- a/src/frontend/packages/store/src/effects/uaa-setup.effects.ts +++ b/src/frontend/packages/store/src/effects/uaa-setup.effects.ts @@ -1,17 +1,18 @@ -import { UaaSetupData, LocalAdminSetupData } from './../types/uaa-setup.types'; -import { Injectable } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; +import { Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { catchError, map, switchMap } from 'rxjs/operators'; +import { isHttpErrorResponse } from '../../../core/src/jetstream.helpers'; import { SETUP_GET_SCOPES, SETUP_SAVE_CONFIG, SetupConsoleGetScopes, - SetupSuccess, SetupFailed, SetupSaveConfig, + SetupSuccess, } from './../actions/setup.actions'; +import { LocalAdminSetupData, UaaSetupData } from './../types/uaa-setup.types'; @Injectable() @@ -22,7 +23,7 @@ export class UAASetupEffect { private actions$: Actions ) { } - getSetupScopesUrl = '/pp/v1/setup.check'; + getSetupScopesUrl = '/pp/v1/setup/check'; saveSetupUrl = '/pp/v1/setup/save'; @Effect() setupGetScopes$ = this.actions$.pipe( @@ -50,10 +51,16 @@ export class UAASetupEffect { })); private fetchError(err): string { - try { - const body = JSON.parse(err._body); - return body.error; - } catch (err) { } + const httpResponse = isHttpErrorResponse(err); + if (httpResponse) { + if (httpResponse.error.error) { + return httpResponse.error.error; + } + try { + const body = JSON.parse(httpResponse.error); + return body; + } catch (err) { } + } return ''; } @@ -63,12 +70,12 @@ export class UAASetupEffect { if ((setupData as UaaSetupData).console_client) { const uaaSetupData = setupData as UaaSetupData; params = params - .set('console_client', uaaSetupData.console_client) - .set('username', uaaSetupData.username) - .set('password', uaaSetupData.password) - .set('skip_ssl_validation', uaaSetupData.skip_ssl_validation.toString() || 'false') - .set('uaa_endpoint', uaaSetupData.uaa_endpoint) - .set('use_sso', uaaSetupData.use_sso.toString() || 'false'); + .set('console_client', uaaSetupData.console_client) + .set('username', uaaSetupData.username) + .set('password', uaaSetupData.password) + .set('skip_ssl_validation', uaaSetupData.skip_ssl_validation.toString() || 'false') + .set('uaa_endpoint', uaaSetupData.uaa_endpoint) + .set('use_sso', uaaSetupData.use_sso.toString() || 'false'); if (uaaSetupData.console_client_secret) { params = params.append('console_client_secret', uaaSetupData.console_client_secret); } From d49d9cc3b2a37849e6d1a3eebe6d6a4010686ddf Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Tue, 7 Jan 2020 12:39:33 +0000 Subject: [PATCH 10/10] Unit test fixes --- .../tile-selector-tile/tile-selector-tile.component.html | 2 +- .../components/tile-selector/tile-selector.component.spec.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html index 301821bdac..155b4b7885 100644 --- a/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html +++ b/src/frontend/packages/core/src/shared/components/tile-selector-tile/tile-selector-tile.component.html @@ -1,4 +1,4 @@ -
+
{{ tile.graphic.matIcon }} diff --git a/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.spec.ts b/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.spec.ts index f4bb302e38..08d6648f88 100644 --- a/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.spec.ts +++ b/src/frontend/packages/core/src/shared/components/tile-selector/tile-selector.component.spec.ts @@ -1,7 +1,8 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { MDAppModule } from '../../../core/md.module'; import { TileSelectorComponent } from './tile-selector.component'; -import { MDAppModule } from '../../../core/md.module'; +import { TileSelectorTileComponent } from './../tile-selector-tile/tile-selector-tile.component'; describe('TileSelectorComponent', () => { let component: TileSelectorComponent; @@ -12,7 +13,7 @@ describe('TileSelectorComponent', () => { imports: [ MDAppModule ], - declarations: [TileSelectorComponent] + declarations: [TileSelectorComponent, TileSelectorTileComponent] }) .compileComponents(); }));