Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ osmt.security.role.curator=ROLE_Osmt_Curator
osmt.security.role.view=ROLE_Osmt_View
osmt.security.scope.read=SCOPE_osmt.read
```
* NOTE: if app.enableRoles=false, all endpoints will be exposed!!
* NOTE: if app.enableRoles=false, all endpoints will be accessible by any authenticated user.
* You can use these values, or you can provide your own based on your own authorization tooling. For Okta, you will need to use the uppercase `ROLE_` prefix on your role.
* `read` is a scope, not a role. This is for machine-to-machine access, rather than for authenticated OSMT users.

Expand Down
2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"lint": "./node_modules/@angular/cli/bin/ng lint",
"e2e": "./node_modules/@angular/cli/bin/ng e2e",
"ci-test": "./node_modules/@angular/cli/bin/ng test --no-watch --no-progress --karma-config=karma.ci.conf.js",
"clean": "rm -rf dist; rm -rf coverage; rm -rf reports; rm -rf test-results; rm -rf node_modules"
"clean": "rm -rf ../api/src/main/resources/ui/*; rm -rf coverage; rm -rf reports; rm -rf test-results; rm -rf node_modules"
},
"private": true,
"dependencies": {
Expand Down
20 changes: 10 additions & 10 deletions ui/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {ManageCollectionComponent} from "./collection/detail/manage-collection.c
import {PublishCollectionComponent} from "./collection/detail/publish-collection.component";
import {CollectionSkillSearchComponent} from "./collection/collection-skill-search.component";
import {BatchImportComponent} from "./richskill/import/batch-import.component";
import { ACTION_ROLES } from "./auth/auth-roles"
import { ActionByRoles, ButtonAction } from "./auth/auth-roles"


const routes: Routes = [
Expand All @@ -33,7 +33,7 @@ const routes: Routes = [
component: RichSkillFormComponent,
canActivate: [AuthGuard],
data: {
roles: ACTION_ROLES.SKILLS_CREATE
roles: ActionByRoles.get(ButtonAction.SkillCreate)
},
canDeactivate: [FormDirtyGuard]
},
Expand All @@ -47,7 +47,7 @@ const routes: Routes = [
component: RichSkillFormComponent,
canActivate: [AuthGuard],
data: {
roles: ACTION_ROLES.SKILL_UPDATE
roles: ActionByRoles.get(ButtonAction.SkillUpdate)
},
canDeactivate: [FormDirtyGuard]
},
Expand All @@ -57,7 +57,7 @@ const routes: Routes = [
canActivate: [AuthGuard],
canDeactivate: [FormDirtyGuard],
data: {
roles: ACTION_ROLES.SKILLS_CREATE
roles: ActionByRoles.get(ButtonAction.SkillCreate)
},
},
// manage skill
Expand All @@ -75,7 +75,7 @@ const routes: Routes = [
component: BatchImportComponent,
canActivate: [AuthGuard],
data: {
roles: ACTION_ROLES.SKILLS_CREATE
roles: ActionByRoles.get(ButtonAction.SkillCreate)
},
},

Expand All @@ -86,7 +86,7 @@ const routes: Routes = [
component: CollectionFormComponent,
canActivate: [AuthGuard],
data: {
roles: ACTION_ROLES.COLLECTION_CREATE
roles: ActionByRoles.get(ButtonAction.CollectionCreate)
},
canDeactivate: [FormDirtyGuard]
},
Expand All @@ -100,7 +100,7 @@ const routes: Routes = [
component: CollectionFormComponent,
canActivate: [AuthGuard],
data: {
roles: ACTION_ROLES.COLLECTION_UPDATE
roles: ActionByRoles.get(ButtonAction.CollectionUpdate)
},
canDeactivate: [FormDirtyGuard]
},
Expand All @@ -114,23 +114,23 @@ const routes: Routes = [
component: PublishCollectionComponent,
canActivate: [AuthGuard],
data: {
roles: ACTION_ROLES.COLLECTION_PUBLISH
roles: ActionByRoles.get(ButtonAction.CollectionPublish)
},
},
// find skills to add to a collection
{path: "collections/:uuid/add-skills",
component: CollectionSkillSearchComponent,
canActivate: [AuthGuard],
data: {
roles: ACTION_ROLES.COLLECTION_SKILLS_UPDATE
roles: ActionByRoles.get(ButtonAction.CollectionSkillsUpdate)
},
},
// find a collection to add a selection of skills to
{path: "collections/add-skills",
component: AddSkillsCollectionComponent,
canActivate: [AuthGuard],
data: {
roles: ACTION_ROLES.COLLECTION_SKILLS_UPDATE
roles: ActionByRoles.get(ButtonAction.CollectionSkillsUpdate)
},
},
// collections library
Expand Down
32 changes: 21 additions & 11 deletions ui/src/app/auth/auth-roles.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
// Default values of OSMT Roles
const OSMT_ADMIN = "ROLE_Osmt_Admin"
const OSMT_CURATOR = "ROLE_Osmt_Curator"
export const OSMT_ADMIN = "ROLE_Osmt_Admin"
export const OSMT_CURATOR = "ROLE_Osmt_Curator"

export const ENABLE_ROLES = false

export const ACTION_ROLES : any = {
SKILL_UPDATE : [OSMT_ADMIN, OSMT_CURATOR],
SKILLS_CREATE : [OSMT_ADMIN, OSMT_CURATOR],
SKILL_PUBLISH : [OSMT_ADMIN],
COLLECTION_CREATE : [OSMT_ADMIN, OSMT_CURATOR],
COLLECTION_PUBLISH : [OSMT_ADMIN],
COLLECTION_UPDATE : [OSMT_ADMIN, OSMT_CURATOR],
COLLECTION_SKILLS_UPDATE : [OSMT_ADMIN]
export enum ButtonAction {
SkillUpdate,
SkillCreate,
SkillPublish,
CollectionUpdate,
CollectionCreate,
CollectionPublish,
CollectionSkillsUpdate
}

export const ActionByRoles = new Map<number, string[]>([
[ButtonAction.SkillUpdate, [OSMT_ADMIN, OSMT_CURATOR]],
[ButtonAction.SkillCreate, [OSMT_ADMIN, OSMT_CURATOR]],
[ButtonAction.SkillPublish, [OSMT_ADMIN]],
[ButtonAction.CollectionUpdate, [OSMT_ADMIN, OSMT_CURATOR]],
[ButtonAction.CollectionCreate, [OSMT_ADMIN, OSMT_CURATOR]],
[ButtonAction.CollectionPublish, [OSMT_ADMIN]],
[ButtonAction.CollectionSkillsUpdate, [OSMT_ADMIN]],
]);

6 changes: 3 additions & 3 deletions ui/src/app/auth/auth-service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ENABLE_ROLES, ACTION_ROLES} from "./auth-roles";
import {ENABLE_ROLES, ButtonAction, ActionByRoles} from "./auth-roles";
import { Injectable } from "@angular/core"
import { Router } from "@angular/router"
import { DEFAULT_INTERRUPTSOURCES, Idle } from "@ng-idle/core"
Expand Down Expand Up @@ -81,9 +81,9 @@ export class AuthService extends Whitelabelled implements IAuthService {
return false
}

isEnabledByRoles(key : string): boolean {
isEnabledByRoles(buttonAction : ButtonAction): boolean {
if (ENABLE_ROLES) {
const allowedRoles = ACTION_ROLES[key];
const allowedRoles = ActionByRoles.get(buttonAction) ?? [];
const userRoles = this.getRole()?.split(",");
return this.hasRole(allowedRoles, userRoles);
}
Expand Down
4 changes: 2 additions & 2 deletions ui/src/app/auth/auth.guard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AuthService } from "./auth-service"
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot} from "@angular/router"
import { HttpClientTestingModule } from "@angular/common/http/testing"
import { AuthServiceStub, RouterStub } from "../../../test/resource/mock-stubs"
import {ACTION_ROLES, ENABLE_ROLES} from "./auth-roles"
import {ActionByRoles, ButtonAction, ENABLE_ROLES} from "./auth-roles"


describe("AuthGuard", () => {
Expand Down Expand Up @@ -38,7 +38,7 @@ describe("AuthGuard", () => {
it("should return true", () => {
// Arrange
const route = Object.assign({}, ActivatedRouteSnapshot.prototype, {
data: {roles: ACTION_ROLES.SKILLS_CREATE}
data: {roles: ActionByRoles.get(ButtonAction.SkillCreate)}
})

// Act and Assert
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/auth/auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Injectable} from "@angular/core"
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from "@angular/router"
import {ENABLE_ROLES, ACTION_ROLES} from "./auth-roles"
import {ENABLE_ROLES} from "./auth-roles"
import {AuthService} from "./auth-service"
import {ToastService} from "../toast/toast.service"

Expand Down
13 changes: 7 additions & 6 deletions ui/src/app/collection/collections-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {TableActionDefinition} from "../table/skills-library-table/has-action-de
import {TableActionBarComponent} from "../table/skills-library-table/table-action-bar.component"
import {Whitelabelled} from "../../whitelabel";
import {AuthService} from "../auth/auth-service";
import {ButtonAction} from "../auth/auth-roles";


@Component({
Expand Down Expand Up @@ -115,33 +116,33 @@ export class CollectionsListComponent extends Whitelabelled {

publishVisible(collection?: ApiCollectionSummary): boolean {
if (collection !== undefined) {
return collection.publishDate === undefined && this.authService.isEnabledByRoles("COLLECTION_PUBLISH")
return collection.publishDate === undefined && this.authService.isEnabledByRoles(ButtonAction.CollectionPublish)
} else if ((this.selectedCollections?.length ?? 0) === 0) {
return false
} else {
const unpublishCollection = this.selectedCollections?.find(s => s.publishDate === undefined)
return (unpublishCollection !== undefined) && (this.authService.isEnabledByRoles("COLLECTION_PUBLISH"))
return (unpublishCollection !== undefined) && this.authService.isEnabledByRoles(ButtonAction.CollectionPublish)
}
}

archiveVisible(collection?: ApiCollectionSummary): boolean {
if (collection !== undefined) {
return !checkArchived(collection) && this.authService.isEnabledByRoles("COLLECTION_UPDATE")
return !checkArchived(collection) && this.authService.isEnabledByRoles(ButtonAction.CollectionUpdate)
} else if ((this.selectedCollections?.length ?? 0) === 0) {
return false
} else {
const unarchCollection = this.selectedCollections?.find(s => !checkArchived(s))
return unarchCollection !== undefined && this.authService.isEnabledByRoles("COLLECTION_UPDATE")
return unarchCollection !== undefined && this.authService.isEnabledByRoles(ButtonAction.CollectionUpdate)
}
}
unarchiveVisible(collection?: ApiCollectionSummary): boolean {
if (collection !== undefined) {
return checkArchived(collection) && this.authService.isEnabledByRoles("COLLECTION_UPDATE")
return checkArchived(collection) && this.authService.isEnabledByRoles(ButtonAction.CollectionUpdate)
} else if ((this.selectedCollections?.length ?? 0) === 0) {
return false
} else {
const archCollection = this.selectedCollections?.find(checkArchived)
return archCollection !== undefined && this.authService.isEnabledByRoles("COLLECTION_UPDATE")
return archCollection !== undefined && this.authService.isEnabledByRoles(ButtonAction.CollectionUpdate)
}
}

Expand Down
11 changes: 6 additions & 5 deletions ui/src/app/collection/detail/manage-collection.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {Observable, Subject} from "rxjs"
import {TableActionBarComponent} from "../../table/skills-library-table/table-action-bar.component"
import {Title} from "@angular/platform-browser";
import {AuthService} from "../../auth/auth-service";
import {ButtonAction} from "../../auth/auth-roles";

@Component({
selector: "app-manage-collection",
Expand Down Expand Up @@ -142,13 +143,13 @@ export class ManageCollectionComponent extends SkillsListComponent implements On
icon: this.addIcon,
primary: !this.collectionHasSkills, // Primary only if there are no skills
callback: () => this.addSkillsAction(),
visible: () => this.authService.isEnabledByRoles("COLLECTION_SKILLS_UPDATE")
visible: () => this.authService.isEnabledByRoles(ButtonAction.CollectionSkillsUpdate)
}),
new TableActionDefinition({
label: "Edit Collection Name",
icon: this.editIcon,
callback: () => this.editAction(),
visible: () => this.authService.isEnabledByRoles("COLLECTION_UPDATE")
visible: () => this.authService.isEnabledByRoles(ButtonAction.CollectionUpdate)
})
]

Expand All @@ -163,7 +164,7 @@ export class ManageCollectionComponent extends SkillsListComponent implements On
label: "Publish Collection",
icon: this.publishIcon,
callback: () => this.publishAction(),
visible: () => this.authService.isEnabledByRoles("COLLECTION_PUBLISH")
visible: () => this.authService.isEnabledByRoles(ButtonAction.CollectionPublish)
}))
}

Expand All @@ -173,15 +174,15 @@ export class ManageCollectionComponent extends SkillsListComponent implements On
label: "Archive Collection ",
icon: this.archiveIcon,
callback: () => this.archiveAction(),
visible: () => this.authService.isEnabledByRoles("COLLECTION_UPDATE")
visible: () => this.authService.isEnabledByRoles(ButtonAction.CollectionUpdate)
}))
} else if (this.collection?.status === PublishStatus.Archived || this.collection?.status === PublishStatus.Deleted) {
actions.push(
new TableActionDefinition({
label: "Unarchive Collection ",
icon: this.unarchiveIcon,
callback: () => this.unarchiveAction(),
visible: () => this.authService.isEnabledByRoles("COLLECTION_UPDATE")
visible: () => this.authService.isEnabledByRoles(ButtonAction.CollectionUpdate)
}))
}
return actions
Expand Down
25 changes: 20 additions & 5 deletions ui/src/app/navigation/abstract-search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@ import {FormControl, FormGroup} from "@angular/forms";
import {SearchService} from "../search/search.service";
import {ActivatedRoute} from "@angular/router";
import {AuthService} from "../auth/auth-service";
import {ButtonAction} from "../auth/auth-roles";

export class AbstractSearchComponent {
searchForm = new FormGroup({
search: new FormControl("")
})

canSkillUpdate: boolean = false
canSkillCreate: boolean = false
canSkillPublish: boolean = false
canCollectionUpdate: boolean = false
canCollectionCreate: boolean = false
canCollectionPublish: boolean = false
canCollectionSkillsUpdate: boolean = false

constructor(protected searchService: SearchService, protected route: ActivatedRoute, protected authService: AuthService) {
this.searchService.searchQuery$.subscribe(apiSearch => {
if (apiSearch === undefined) {
Expand All @@ -21,6 +30,17 @@ export class AbstractSearchComponent {
this.searchForm.setValue({search: queryString})
}
})
this.setEnableFlags()
}

setEnableFlags(): void {
this.canSkillUpdate = this.authService.isEnabledByRoles(ButtonAction.SkillUpdate);
this.canSkillCreate = this.authService.isEnabledByRoles(ButtonAction.SkillCreate);
this.canSkillPublish = this.authService.isEnabledByRoles(ButtonAction.SkillPublish);
this.canCollectionUpdate = this.authService.isEnabledByRoles(ButtonAction.CollectionUpdate);
this.canCollectionCreate = this.authService.isEnabledByRoles(ButtonAction.CollectionCreate);
this.canCollectionPublish = this.authService.isEnabledByRoles(ButtonAction.CollectionPublish);
this.canCollectionSkillsUpdate = this.authService.isEnabledByRoles(ButtonAction.CollectionSkillsUpdate);
}

clearSearch(): boolean {
Expand Down Expand Up @@ -49,9 +69,4 @@ export class AbstractSearchComponent {
}
return false
}

isEnabled(path: string): boolean {
return this.authService.isEnabledByRoles(path);
}

}
6 changes: 3 additions & 3 deletions ui/src/app/navigation/commoncontrols-mobile.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<ul class="m-navBar-x-nav">

<li>
<button class="m-buttonText m-buttonText-onDark" routerLink="/skills/create" type="button" [disabled]="!isEnabled('SKILLS_CREATE')">
<button class="m-buttonText m-buttonText-onDark" routerLink="/skills/create" type="button" [disabled]="!canSkillCreate">
<span class="m-buttonText-x-icon">
<svg class="t-icon" aria-hidden="true">
<use xlink:href="/assets/images/svg-defs.svg#icon-doc"></use>
Expand All @@ -66,7 +66,7 @@
</li>

<li>
<button class="m-buttonText m-buttonText-onDark" routerLink="/collections/create" type="button" [disabled]="!isEnabled('COLLECTION_CREATE')">
<button class="m-buttonText m-buttonText-onDark" routerLink="/collections/create" type="button" [disabled]="!canCollectionCreate">
<span class="m-buttonText-x-icon">
<svg class="t-icon" aria-hidden="true">
<use xlink:href="/assets/images/svg-defs.svg#icon-collection"></use>
Expand All @@ -77,7 +77,7 @@
</li>

<li>
<button class="m-buttonText m-buttonText-onDark" routerLink="/skills/import" type="button" [disabled]="!isEnabled('SKILLS_CREATE')">
<button class="m-buttonText m-buttonText-onDark" routerLink="/skills/import" type="button" [disabled]="!canSkillCreate">
<span class="m-buttonText-x-icon">
<svg class="t-icon" aria-hidden="true">
<use xlink:href="/assets/images/svg-defs.svg#icon-upload"></use>
Expand Down
6 changes: 3 additions & 3 deletions ui/src/app/navigation/commoncontrols.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,21 @@

<div class="m-commonControls-x-controls">
<div>
<a class="m-button" routerLink="/skills/create" [class.disabled-content]="!isEnabled('SKILLS_CREATE')">
<a class="m-button" routerLink="/skills/create" [class.disabled-content]="!canSkillCreate">
<svg class="m-button-x-icon t-icon">
<use xlink:href="/assets/images/svg-defs.svg#icon-doc"></use>
</svg>
<span class="m-button-x-text">Create RSD</span>
</a>

<a class="m-button" routerLink="/collections/create" [class.disabled-content]="!isEnabled('COLLECTION_CREATE')">
<a class="m-button" routerLink="/collections/create" [class.disabled-content]="!canCollectionCreate">
<svg class="m-button-x-icon t-icon">
<use xlink:href="/assets/images/svg-defs.svg#icon-collection"></use>
</svg>
<span class="m-button-x-text">Create Collection</span>
</a>

<a class="m-button" routerLink="/skills/import" [class.disabled-content]="!isEnabled('SKILLS_CREATE')">
<a class="m-button" routerLink="/skills/import" [class.disabled-content]="!canSkillCreate">
<svg class="m-button-x-icon t-icon">
<use xlink:href="/assets/images/svg-defs.svg#icon-upload"></use>
</svg>
Expand Down
Loading