task #9088 Authorization model should be changed to be Permission based

This commit is contained in:
Efstratios Giannopoulos 2023-10-17 17:13:34 +03:00
parent 9fd30b1198
commit b3a73a50aa
13 changed files with 96 additions and 59 deletions

View File

@ -28,6 +28,7 @@
<dependency>
<groupId>gr.cite</groupId>
<artifactId>validation</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>gr.cite</groupId>

View File

@ -5,6 +5,4 @@ import java.util.EnumSet;
public enum AuthorizationFlags {
None, Permission, Owner;
public static final EnumSet<AuthorizationFlags> OwnerOrPermission = EnumSet.of(Owner, Permission);
public static final EnumSet<AuthorizationFlags> OwnerOrPermissionOrIndicator = EnumSet.of(Owner, Permission);
public static final EnumSet<AuthorizationFlags> OwnerOrPermissionOrIndicatorOrIndicatorAccess = EnumSet.of(Owner, Permission);
}

View File

@ -1,5 +1,6 @@
package eu.eudat.model.builder;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.commons.JsonHandlingService;
import eu.eudat.convention.ConventionService;
import eu.eudat.data.DescriptionTemplateTypeEntity;
@ -24,25 +25,18 @@ import java.util.stream.Collectors;
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class DescriptionTemplateTypeBuilder extends BaseBuilder<DescriptionTemplateType, DescriptionTemplateTypeEntity> {
private final QueryFactory queryFactory;
private final BuilderFactory builderFactory;
private final JsonHandlingService jsonHandlingService;
//private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
@Autowired
public DescriptionTemplateTypeBuilder(
ConventionService conventionService,
QueryFactory queryFactory, BuilderFactory builderFactory, JsonHandlingService jsonHandlingService) {
ConventionService conventionService) {
super(conventionService, new LoggerService(LoggerFactory.getLogger(DescriptionTemplateTypeBuilder.class)));
this.queryFactory = queryFactory;
this.builderFactory = builderFactory;
this.jsonHandlingService = jsonHandlingService;
}
// public DescriptionTemplateTypeBuilder authorize(EnumSet<AuthorizationFlags> values) {
// this.authorize = values;
// return this;
// }
public DescriptionTemplateTypeBuilder authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values;
return this;
}
@Override
public List<DescriptionTemplateType> build(FieldSet fields, List<DescriptionTemplateTypeEntity> datas) throws MyApplicationException {

View File

@ -11,6 +11,8 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.UUID;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class DescriptionTemplateTypeCensor extends BaseCensor{
@ -22,7 +24,7 @@ public class DescriptionTemplateTypeCensor extends BaseCensor{
this.authService = authService;
}
public void censor(FieldSet fields) {
public void censor(FieldSet fields, UUID userId) {
logger.debug(new DataLogEntry("censoring fields", fields));
if (fields.isEmpty()) return;

View File

@ -1,9 +1,11 @@
package eu.eudat.query;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.commons.enums.Status;
import eu.eudat.commons.scope.UserScope;
import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.data.DescriptionTemplateTypeEntity;
import eu.eudat.model.DescriptionTemplateType;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.query.FieldResolver;
import gr.cite.tools.data.query.QueryBase;
import gr.cite.tools.data.query.QueryContext;
@ -25,7 +27,7 @@ public class DescriptionTemplateTypeQuery extends QueryBase<DescriptionTemplateT
private Collection<UUID> ids;
private Collection<Status> isActives;
private Collection<UUID> excludedIds;
//private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
public DescriptionTemplateTypeQuery like(String value) {
this.like = value;
@ -77,20 +79,20 @@ public class DescriptionTemplateTypeQuery extends QueryBase<DescriptionTemplateT
return this;
}
// public DescriptionTemplateTypeQuery authorize(EnumSet<AuthorizationFlags> values) {
// this.authorize = values;
// return this;
// }
public DescriptionTemplateTypeQuery authorize(EnumSet<AuthorizationFlags> values) {
this.authorize = values;
return this;
}
private final UserScope userScope;
// private final AuthorizationService authService;
private final AuthorizationService authService;
public DescriptionTemplateTypeQuery(
UserScope userScope
//AuthorizationService authService
UserScope userScope,
AuthorizationService authService
) {
this.userScope = userScope;
//this.authService = authService;
this.authService = authService;
}
@Override

View File

@ -1,5 +1,7 @@
package eu.eudat.service;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.authorization.Permission;
import eu.eudat.commons.JsonHandlingService;
import eu.eudat.commons.enums.Status;
import eu.eudat.convention.ConventionService;
@ -12,6 +14,7 @@ import eu.eudat.model.builder.DescriptionTemplateTypeBuilder;
import eu.eudat.model.deleter.DescriptionTemplateTypeDeleter;
import eu.eudat.model.persist.DescriptionTemplateTypePersist;
import eu.eudat.query.DescriptionTemplateTypeQuery;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.deleter.DeleterFactory;
import gr.cite.tools.data.query.QueryFactory;
@ -42,7 +45,7 @@ public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTy
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(DescriptionTemplateTypeServiceImpl.class));
private final EntityManager entityManager;
//private final AuthorizationService authorizationService;
private final AuthorizationService authorizationService;
private final DeleterFactory deleterFactory;
private final BuilderFactory builderFactory;
private final ConventionService conventionService;
@ -55,7 +58,7 @@ public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTy
@Autowired
public DescriptionTemplateTypeServiceImpl(
EntityManager entityManager,
//AuthorizationService authorizationService,
AuthorizationService authorizationService,
DeleterFactory deleterFactory,
BuilderFactory builderFactory,
ConventionService conventionService,
@ -65,7 +68,7 @@ public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTy
QueryFactory queryFactory,
JsonHandlingService jsonHandlingService) {
this.entityManager = entityManager;
//this.authorizationService = authorizationService;
this.authorizationService = authorizationService;
this.deleterFactory = deleterFactory;
this.builderFactory = builderFactory;
this.conventionService = conventionService;
@ -79,7 +82,7 @@ public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTy
public DescriptionTemplateType persist(DescriptionTemplateTypePersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException {
logger.debug(new MapLogEntry("persisting data descriptionTemplateType").And("model", model).And("fields", fields));
//this.authorizationService.authorizeForce(Permission.EditDescriptionTemplateType);
this.authorizationService.authorizeForce(Permission.EditDescriptionTemplateType);
Boolean isUpdate = this.conventionService.isValidGuid(model.getId());
@ -102,14 +105,13 @@ public class DescriptionTemplateTypeServiceImpl implements DescriptionTemplateTy
this.entityManager.flush();
this.eventBroker.emit(new DescriptionTemplateTypeTouchedEvent(data.getId()));
//return this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).authorize(AuthorizationFlags.OwnerOrPermissionOrDescriptionTemplateType).build(BaseFieldSet.build(fields, DescriptionTemplateType._id), data);
return this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).build(BaseFieldSet.build(fields, DescriptionTemplateType._id), data);
return this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(BaseFieldSet.build(fields, DescriptionTemplateType._id), data);
}
public void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException {
logger.debug("deleting dataset: {}", id);
//this.authorizationService.authorizeForce(Permission.DeleteDescriptionTemplateType);
this.authorizationService.authorizeForce(Permission.DeleteDescriptionTemplateType);
this.deleterFactory.deleter(DescriptionTemplateTypeDeleter.class).deleteAndSaveByIds(List.of(id));
}

View File

@ -1,5 +1,6 @@
package eu.eudat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
@ -28,6 +29,7 @@ public class EuDatApplication extends SpringBootServletInitializer {
@Primary
public ObjectMapper primaryObjectMapper() {
return JsonMapper.builder().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.serializationInclusion(JsonInclude.Include.NON_NULL)
.addModule(new JavaTimeModule()).build();
}

View File

@ -1,6 +1,7 @@
package eu.eudat.controllers.v2;
import eu.eudat.audit.AuditableAction;
import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.data.DescriptionTemplateTypeEntity;
import eu.eudat.logic.security.claims.ClaimedAuthorities;
import eu.eudat.model.DescriptionTemplateType;
@ -72,14 +73,12 @@ public class DescriptionTemplateTypeV2Controller {
public QueryResult<DescriptionTemplateType> Query(@RequestBody DescriptionTemplateTypeLookup lookup) throws MyApplicationException, MyForbiddenException {
logger.debug("querying {}", DescriptionTemplateType.class.getSimpleName());
//this.censorFactory.censor(DescriptionTemplateTypeCensor.class).censor(lookup.getProject(), null);
this.censorFactory.censor(DescriptionTemplateTypeCensor.class).censor(lookup.getProject(), null);
DescriptionTemplateTypeQuery query = lookup.enrich(this.queryFactory);
//DescriptionTemplateTypeQuery query = lookup.enrich(this.queryFactory).authorize(AuthorizationFlags.OwnerOrPermissionOrDescriptionTemplateType);
DescriptionTemplateTypeQuery query = lookup.enrich(this.queryFactory).authorize(AuthorizationFlags.OwnerOrPermission);
List<DescriptionTemplateTypeEntity> data = query.collectAs(lookup.getProject());
//List<DescriptionTemplateType> models = this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).authorize(AuthorizationFlags.OwnerOrPermissionOrDescriptionTemplateType).build(lookup.getProject(), data);
List<DescriptionTemplateType> models = this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).build(lookup.getProject(), data);
List<DescriptionTemplateType> models = this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(lookup.getProject(), data);
long count = (lookup.getMetadata() != null && lookup.getMetadata().getCountAll()) ? query.count() : models.size();
this.auditService.track(AuditableAction.DescriptionTemplateType_Query, "lookup", lookup);
@ -92,12 +91,10 @@ public class DescriptionTemplateTypeV2Controller {
public DescriptionTemplateType Get(@PathVariable("id") UUID id, FieldSet fieldSet, Locale locale) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + DescriptionTemplateType.class.getSimpleName()).And("id", id).And("fields", fieldSet));
//this.censorFactory.censor(DescriptionTemplateTypeCensor.class).censor(fieldSet, null);
this.censorFactory.censor(DescriptionTemplateTypeCensor.class).censor(fieldSet, null);
DescriptionTemplateTypeQuery query = this.queryFactory.query(DescriptionTemplateTypeQuery.class).ids(id);
DescriptionTemplateType model = this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).build(fieldSet, query.firstAs(fieldSet));
//DescriptionTemplateTypeQuery query = this.queryFactory.query(DescriptionTemplateTypeQuery.class).authorize(AuthorizationFlags.OwnerOrPermissionOrDescriptionTemplateType).ids(id);
//DescriptionTemplateType model = this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).authorize(AuthorizationFlags.OwnerOrPermissionOrDescriptionTemplateType).build(fieldSet, query.firstAs(fieldSet));
DescriptionTemplateTypeQuery query = this.queryFactory.query(DescriptionTemplateTypeQuery.class).authorize(AuthorizationFlags.OwnerOrPermission).ids(id);
DescriptionTemplateType model = this.builderFactory.builder(DescriptionTemplateTypeBuilder.class).authorize(AuthorizationFlags.OwnerOrPermission).build(fieldSet, query.firstAs(fieldSet));
if (model == null) throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, DescriptionTemplateType.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.auditService.track(AuditableAction.DescriptionTemplateType_Lookup, Map.ofEntries(

View File

@ -23,7 +23,7 @@ permissions:
allowAuthenticated: false
# ViewPage Permissions
ViewDatasetPage:
ViewDescriptionTemplateTypePage:
roles:
- Admin
clients: [ ]

View File

@ -3,6 +3,7 @@ import { RouterModule, Routes } from '@angular/router';
import { ReloadHelperComponent } from '@app/ui/misc/reload-helper/reload-helper.component';
import { Oauth2DialogComponent } from './ui/misc/oauth2-dialog/oauth2-dialog.component';
import { AppComponent } from './app.component';
import { AppPermission } from './core/common/enum/permission.enum';
const appRoutes: Routes = [
{
@ -102,9 +103,12 @@ const appRoutes: Routes = [
loadChildren: () => import('./ui/admin/description-types/description-types.module').then(m => m.DescriptionTypesModule),
data: {
breadcrumb: true,
title: 'GENERAL.TITLES.DESCRIPTION-TYPES'
title: 'GENERAL.TITLES.DESCRIPTION-TYPES',
authContext: {
permissions: [AppPermission.ViewDescriptionTemplateTypePage]
}
},
},
{
path: 'contact-support',
loadChildren: () => import('./ui/contact/contact.module').then(m => m.ContactModule),

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, CanLoad, Route, Router, RouterStateSnapshot } from '@angular/router';
import { AuthService } from './services/auth/auth.service';
import { AuthService, ResolutionContext } from './services/auth/auth.service';
import { from, Observable, of as observableOf } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
@ -11,25 +11,32 @@ export class AuthGuard implements CanActivate, CanLoad {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
const url: string = state.url;
return this.applyGuard(url);
const authContext = route.data ? route.data['authContext'] as ResolutionContext : null;
return this.applyGuard(url, authContext);
}
canLoad(route: Route): Observable<boolean> {
const url = `/${route.path}`;
return this.applyGuard(url);
const authContext = route.data ? route.data['authContext'] as ResolutionContext : null;
return this.applyGuard(url, authContext);
}
private applyGuard(url: string) {
return this.checkLogin(url).pipe(tap(loggedIn => {
private applyGuard(url: string, authContext: ResolutionContext) {
return this.checkLogin(url, authContext).pipe(tap(loggedIn => {
if (!loggedIn) {
this.router.navigate(['/unauthorized'], { queryParams: { returnUrl: url } });
} else {
return true;
const authorized = this.authService.hasAccessToken() && this.authService.authorize(authContext);
if(!authorized){
this.router.navigate(['/unauthorized']);
}else{
return authorized;
}
}
}));
}
private checkLogin(url: string): Observable<boolean> {
private checkLogin(url: string, authContext: ResolutionContext): Observable<boolean> {
if (!this.authService.isLoggedIn()) { return observableOf(false); }
return this.authService.hasAccessToken()

View File

@ -3,11 +3,39 @@ import { RouterModule, Routes } from "@angular/router";
import { AdminAuthGuard } from "@app/core/admin-auth-guard.service";
import { DescriptionTypeEditorComponent } from './editor/description-type-editor.component';
import { DescriptionTypesComponent } from "./listing/description-types.component";
import { AuthGuard } from "@app/core/auth-guard.service";
import { AppPermission } from "@app/core/common/enum/permission.enum";
const routes: Routes = [
{ path: '', component: DescriptionTypesComponent, canActivate: [AdminAuthGuard] },
{ path: 'new', component: DescriptionTypeEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DESCRIPTION-TYPE-NEW' } },
{ path: ':id', component: DescriptionTypeEditorComponent, canActivate: [AdminAuthGuard], data: { title: 'GENERAL.TITLES.DESCRIPTION-TYPE-EDIT' } }
{
path: '',
component: DescriptionTypesComponent,
canActivate: [AuthGuard],
data: {
authContext: {
permissions: [AppPermission.ViewDescriptionTemplateTypePage]
}
},
},
{
path: 'new',
component: DescriptionTypeEditorComponent,
canActivate: [AuthGuard],
data: {
title: 'GENERAL.TITLES.DESCRIPTION-TYPE-NEW',
authContext: {
permissions: [AppPermission.EditDescriptionTemplateType]
}
}
},
{
path: ':id',
component: DescriptionTypeEditorComponent,
canActivate: [AuthGuard],
data: {
title: 'GENERAL.TITLES.DESCRIPTION-TYPE-EDIT'
}
}
]
@NgModule({