fix: keycloak realm issues

This commit is contained in:
Marcel Haag 2023-04-21 10:08:13 +02:00 committed by Cel
parent b4bf6de8f8
commit ed7c70c62d
19 changed files with 2406 additions and 335 deletions

View File

@ -10976,9 +10976,9 @@
}
},
"keycloak-js": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-13.0.1.tgz",
"integrity": "sha512-S9mFX8HHlgw+i2HAIhteccrkffQmUn4CpYcU8ViGnODSBcnaf2YTtLhiiRH/a6SaOBpxmJTN3XVIZbE9d/HyXQ==",
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-14.0.0.tgz",
"integrity": "sha512-35olMBg+Fwr1b3hu3BmyYj4PBn2uoDn7OOO0C1f+4axZhaOhvv47zq7nHG8R3g2QZcHFG5SymdEU6obrahEdJQ==",
"requires": {
"base64-js": "1.3.1",
"js-sha256": "0.9.0"

View File

@ -36,13 +36,13 @@
"@ngxs/store": "^3.7.3",
"chart.js": "^4.2.1",
"eva-icons": "^1.1.3",
"font-awesome": "^4.7.0",
"i18n-iso-countries": "^6.8.0",
"jwt-decode": "^3.1.2",
"keycloak-angular": "^8.4.0",
"keycloak-js": "^13.0.1",
"keycloak-angular": "^8.3.0",
"keycloak-js": "^14.0.0",
"moment": "^2.29.1",
"moment-timezone": "latest",
"font-awesome": "^4.7.0",
"ng-mocks": "^13.4.2",
"ngx-moment": "^5.0.0",
"ngx-take-until-destroy": "^5.4.0",

View File

@ -142,13 +142,14 @@ export class HeaderComponent implements OnInit {
}
onClickLogOut(): void {
console.info('Logging out...');
// ToDo: Redirect user to Landing page from Issue #142 https://github.com/Marcel-Haag/security-c4po/issues/143
// ToDo: Fix Redirect URI in Keycloak Setting
/*this.keycloakService.logout(`http://auth-server/realms/${environment.keycloakclientId}/protocol/openid-connect/logout`).then(() => {
// ToDo: Has to be implemented once HTTPS works
/*this.userService.logout().then(() => {
console.warn('logout success');
// Route user back to default page
this.router.navigate([Route.HOME]).then(() => {
// Reset User props from store
this.keycloakService.clearToken();
this.store.dispatch(new ResetSession());
}, err => {
console.error(err);

View File

@ -11,7 +11,7 @@ import {
NbListModule,
NbButtonModule,
NbTooltipModule,
NbActionsModule, NbUserModule, NbContextMenuModule
NbActionsModule, NbUserModule, NbContextMenuModule, NbSortDirective
} from '@nebular/theme';
import {TranslateModule} from '@ngx-translate/core';
import {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
@ -32,7 +32,7 @@ import {VersionTagModule} from '@shared/widgets/version-tag/version-tag.module';
declarations: [
ObjectiveHeaderComponent,
ObjectiveCategoriesComponent,
ObjectiveTableComponent,
ObjectiveTableComponent
],
imports: [
CommonModule,
@ -67,7 +67,10 @@ import {VersionTagModule} from '@shared/widgets/version-tag/version-tag.module';
exports: [
ObjectiveHeaderComponent,
ObjectiveCategoriesComponent,
ObjectiveTableComponent,
ObjectiveTableComponent
],
providers: [
NbSortDirective
]
})
export class ObjectiveOverviewModule {

View File

@ -1,5 +1,5 @@
<div class="pentest-table">
<table [nbTreeGrid]="dataSource">
<table [nbTreeGrid]="dataSource" nbsort>
<!--ToDo: Add the click event to every td manually except the actions column actions-->
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="columns"></tr>
<tr nbTreeGridRow *nbTreeGridRowDef="let pentest; columns: columns"

View File

@ -1,9 +1,9 @@
import {Component, OnInit} from '@angular/core';
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
import {Pentest, ObjectiveEntry, transformPentestsToObjectiveEntries} from '@shared/models/pentest.model';
import {NbGetters, NbSortDirection, NbSortRequest, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
import {ObjectiveEntry, Pentest, transformPentestsToObjectiveEntries} from '@shared/models/pentest.model';
import {PentestService} from '@shared/services/api/pentest.service';
import {Store} from '@ngxs/store';
import {PROJECT_STATE_NAME, ProjectState} from '@shared/stores/project-state/project-state';
import {ProjectState} from '@shared/stores/project-state/project-state';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {catchError, filter, switchMap, tap} from 'rxjs/operators';
import {BehaviorSubject, Observable, of} from 'rxjs';
@ -71,6 +71,12 @@ export class ObjectiveTableComponent implements OnInit {
}
});
this.loadPentestData();
this.changeSortTable()
this.dataSource.sort({column: ObjectiveColumns.TEST_ID, direction: NbSortDirection.DESCENDING});
}
private changeSortTable(): void {
this.dataSource.sort({column: ObjectiveColumns.TEST_ID, direction: NbSortDirection.DESCENDING});
}
loadPentestData(): void {

View File

@ -5,6 +5,7 @@ export const environment = {
keycloakURL: 'http://localhost:8080/auth',
keycloakrealm: 'c4po_realm_local',
keycloakclientId: 'c4po_local',
keycloakRedirectUri: 'https://localhost:4200/*',
// backend service
apiEndpoint: 'http://localhost:8443',

View File

@ -10,6 +10,7 @@ export const environment = {
keycloakURL: 'http://localhost:8080/auth',
keycloakrealm: 'c4po_realm_local',
keycloakclientId: 'c4po_local',
keycloakRedirectUri: 'https://localhost:4200/*',
// backend service
apiEndpoint: 'http://localhost:8443',

View File

@ -36,6 +36,7 @@
type="formText" required fullWidth
id="{{formArray[1].fieldName}}" nbInput
class="form-field form-textarea"
rows="{{formArray[1].controlsConfig[0].value !== '' ? formArray[1].controlsConfig[0].value.split(getRowsFromString).length + 1 : 2}}"
[status]="commentFormGroup.get(formArray[1].fieldName).dirty ? (commentFormGroup.get(formArray[1].fieldName).invalid ? 'danger' : 'basic') : 'basic'"
placeholder="{{formArray[1].placeholder | translate}} *">
</textarea>

View File

@ -28,6 +28,7 @@ export class CommentDialogComponent implements OnInit {
// HTML only
readonly fa = FA;
readonly getRowsFromString = /\r|\r\n|\n/;
constructor(
@Inject(NB_DIALOG_CONFIG) private data: GenericDialogData,

View File

@ -36,6 +36,7 @@
type="formText" required fullWidth
id="{{formArray[2].fieldName}}" nbInput
class="form-field form-text"
rows="{{formArray[2].controlsConfig[0].value !== '' ? formArray[2].controlsConfig[0].value.split(getRowsFromString).length + 1 : 2}}"
[status]="findingFormGroup.get(formArray[2].fieldName).dirty ? (findingFormGroup.get(formArray[2].fieldName).invalid ? 'danger' : 'basic') : 'basic'"
placeholder="{{formArray[2].placeholder | translate}} *">
</textarea>
@ -57,6 +58,7 @@
type="formText" required fullWidth
id="{{formArray[3].fieldName}}" nbInput
class="form-field form-text"
rows="{{formArray[3].controlsConfig[0].value !== '' ? formArray[3].controlsConfig[0].value.split(getRowsFromString).length + 1 : 2}}"
[status]="findingFormGroup.get(formArray[3].fieldName).dirty ? (findingFormGroup.get(formArray[3].fieldName).invalid ? 'danger' : 'basic') : 'basic'"
placeholder="{{formArray[3].placeholder | translate}} *">
</textarea>
@ -132,6 +134,7 @@
type="text" required fullWidth
id="{{formArray[5].fieldName}}" nbInput
class="form-field form-textarea"
rows="{{formArray[5].controlsConfig[0].value !== '' ? formArray[5].controlsConfig[0].value.split(getRowsFromString).length + 1 : 2}}"
[status]="findingFormGroup.get(formArray[5].fieldName).dirty ? (findingFormGroup.get(formArray[5].fieldName).invalid ? 'danger' : 'basic') : 'basic'"
placeholder="{{formArray[5].placeholder | translate}} *">
</textarea>
@ -153,6 +156,7 @@
type="text" fullWidth
id="{{formArray[6].fieldName}}" nbInput
class="form-field form-textarea"
rows="{{formArray[6].controlsConfig[0].value !== '' ? formArray[6].controlsConfig[0].value.split(getRowsFromString).length + 1 : 2}}"
[status]="findingFormGroup.get(formArray[6].fieldName).dirty ? (findingFormGroup.get(formArray[6].fieldName).invalid ? 'danger' : 'basic') : 'basic'"
placeholder="{{formArray[6].placeholder | translate}}">
</textarea>

View File

@ -21,25 +21,6 @@ import {Store} from '@ngxs/store';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FindingDialogComponent implements OnInit {
// form control elements
findingFormGroup: FormGroup;
formArray: GenericFormFieldConfig[];
dialogData: GenericDialogData;
// HTML only
readonly fa = FA;
severity: Severity = Severity.LOW;
readonly severityTexts: Array<SeverityText> = [
{value: Severity.LOW, translationText: 'severities.low'},
{value: Severity.MEDIUM, translationText: 'severities.medium'},
{value: Severity.HIGH, translationText: 'severities.high'},
{value: Severity.CRITICAL, translationText: 'severities.critical'}
];
// ToDo: Adjust for edit finding dialog to include existing urls
affectedUrls: string[] = [];
initialAffectedUrls: string[] = [];
constructor(
@Inject(NB_DIALOG_CONFIG) private data: GenericDialogData,
@ -51,6 +32,26 @@ export class FindingDialogComponent implements OnInit {
private store: Store
) {
}
// form control elements
findingFormGroup: FormGroup;
formArray: GenericFormFieldConfig[];
dialogData: GenericDialogData;
// HTML only
readonly fa = FA;
readonly getRowsFromString = /\r|\r\n|\n/;
severity: Severity = Severity.LOW;
readonly severityTexts: Array<SeverityText> = [
{value: Severity.LOW, translationText: 'severities.low'},
{value: Severity.MEDIUM, translationText: 'severities.medium'},
{value: Severity.HIGH, translationText: 'severities.high'},
{value: Severity.CRITICAL, translationText: 'severities.critical'}
];
// ToDo: Adjust for edit finding dialog to include existing urls
affectedUrls: string[] = [];
initialAffectedUrls: string[] = [];
ngOnInit(): void {
this.findingFormGroup = this.generateFormCreationFieldArray();

View File

@ -49,6 +49,7 @@
type="formText" required fullWidth
id="{{fieldConfig.fieldName}}" nbInput
class="form-field form-textarea"
rows="{{fieldConfig.controlsConfig[0].value !== '' ? fieldConfig.controlsConfig[0].value.split(getRowsFromString).length + 1 : 2}}"
[status]="projectFormGroup.get(fieldConfig.fieldName).dirty ? (projectFormGroup.get(fieldConfig.fieldName).invalid ? 'danger' : 'basic') : 'basic'"
placeholder="{{fieldConfig.placeholder | translate}}">
</textarea>

View File

@ -26,6 +26,7 @@ export class ProjectDialogComponent implements OnInit {
// HTML only
readonly fa = FA;
readonly getRowsFromString = /\r|\r\n|\n/;
state: ReportState = ReportState.NEW;
readonly reportStateTexts = reportStateTexts;

View File

@ -87,7 +87,7 @@ export class ProjectDialogService {
labelKey: 'project.summary.label',
placeholder: 'project.summary.placeholder',
controlsConfig: [
{value: project ? project.summary : '', disabled: !project},
{value: project && project.summary ? project.summary : '', disabled: !project},
[project ? Validators.required : []]
],
errors: [

View File

@ -1,10 +1,12 @@
import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {User} from '../../models/user.model';
import {from, Observable, Subscriber} from 'rxjs';
import {from, Observable, of, Subscriber} from 'rxjs';
import {Store} from '@ngxs/store';
import {KeycloakService} from 'keycloak-angular';
import {map} from 'rxjs/operators';
import {environment} from '../../../environments/environment';
import {Route} from '@shared/models/route.enum';
@Injectable({
providedIn: 'root'
@ -39,6 +41,42 @@ export class UserService {
return from(this.keycloakService.loadUserProfile()) as Observable<User>;
}
public logout(): Promise<void> {
return this.keycloakService.logout();
}
// ToDo: Change update profile propterties OR ...
// ...In our angular application, best way to change password was to create “button” with “hardcoded” link to:
// https://keycloakUrl/realms/myrealm/protocol/openid-connect/auth 58
// ?response_type=code
// &client_id=myclient
// &redirect_uri=myAppUrl
// &kc_action=UPDATE_PASSWORD
// ToDo: Or use API
// https://stackoverflow.com/questions/33910615/is-there-an-api-call-for-changing-user-password-on-keycloak
// ToDo: https://www.keycloak.org/docs/latest/server_development/
public changeUserProperties(): Observable<any> {
// ToDo: There is a kc_action parameter available in keycloak to let application force required actions.
/*../realms/myrealm/protocol/openid-connect/auth
?response_type=code
&client_id=myclient
&redirect_uri=https://myclient.com
&kc_action=update_profile*/
return of();
}
// ToDo: https://keycloak.discourse.group/t/integrate-change-password-from-account-console-into-own-webapp/12300
public changePassword(): Observable<any> {
// ToDo: To force (or allow) a password update, use kc_action=UPDATE_PASSWORD
/*../realms/myrealm/protocol/openid-connect/auth
?response_type=code
&client_id=myclient
&redirect_uri=https://myclient.com
&kc_action=update_profile*/
return of();
}
private getToken(): Observable<string> {
return new Observable((observer: Subscriber<any>): void => {
this.keycloakService.getToken().then(token => {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,9 @@ services:
c4po-keycloak:
container_name: c4po-keycloak
image: quay.io/keycloak/keycloak:20.0.0
environment:
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=admin
volumes:
- ./cfg/c4po_realm_export.json/:/opt/keycloak/data/import/c4po_realm_export.json
ports: