Change getSiteAreas logic.
MODIFY
src/authorization/AuthorizationsDefinition.ts
src/authorization/AuthorizationsDefinition.ts
@@ -41,7 +41,10 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
{ resource: Entity.COMPANY, action: [Action.CREATE, Action.UPDATE, Action.DELETE], attributes: ['*'] },
{ resource: Entity.SITES, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.SITE, action: [Action.CREATE, Action.READ, Action.UPDATE, Action.DELETE], attributes: ['*'] },
- { resource: Entity.SITE_AREAS, action: Action.LIST, attributes: ['*'] },
+ { resource: Entity.SITE_AREAS, action: Action.LIST, attributes: [
+ 'id', 'name', 'siteID', 'maximumPower', 'voltage', 'numberOfPhases', 'accessControl', 'smartCharging', 'address',
+ 'site.id', 'site.name', 'issuer', 'distanceMeters', 'createdOn', 'createdBy', 'lastChangedOn', 'lastChangedBy'
+ ] },
{ resource: Entity.SITE_AREA, action: [Action.CREATE, Action.READ, Action.UPDATE, Action.DELETE], attributes: ['*'] },
{ resource: Entity.CHARGING_STATIONS, action: [Action.LIST, Action.IN_ERROR], attributes: ['*'] },
{
@@ -155,7 +158,15 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
// -----------------------------------------------------------------------------------------------
{ resource: Entity.SITES, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.SITE, action: Action.READ, attributes: ['*'] },
- { resource: Entity.SITE_AREAS, action: Action.LIST, attributes: ['*'] },
+ { resource: Entity.SITE_AREAS, action: Action.LIST,
+ condition: {
+ Fn: 'custom:dynamicAuthorizationFilters',
+ args: { filters: ['AssignedSites'] }
+ },
+ attributes: [
+ 'id', 'name', 'siteID', 'maximumPower', 'voltage', 'numberOfPhases', 'accessControl', 'smartCharging', 'address',
+ 'site.id', 'site.name', 'issuer', 'distanceMeters', 'createdOn', 'createdBy', 'lastChangedOn', 'lastChangedBy'
+ ] },
{ resource: Entity.SITE_AREA, action: Action.READ, attributes: ['*'] },
{ resource: Entity.CHARGING_STATIONS, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.CHARGING_STATION, action: [Action.READ], attributes: ['*'] },
@@ -247,7 +258,10 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
'id', 'name', 'issuer', 'logo', 'address'] },
{ resource: Entity.SITES, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.SITE, action: Action.READ, attributes: ['*'] },
- { resource: Entity.SITE_AREAS, action: Action.LIST, attributes: ['*'] },
+ { resource: Entity.SITE_AREAS, action: Action.LIST, attributes: [
+ 'id', 'name', 'siteID', 'maximumPower', 'voltage', 'numberOfPhases', 'accessControl', 'smartCharging', 'address',
+ 'site.id', 'site.name', 'issuer', 'distanceMeters', 'createdOn', 'createdBy', 'lastChangedOn', 'lastChangedBy'
+ ] },
{ resource: Entity.SITE_AREA, action: Action.READ, attributes: ['*'] },
{ resource: Entity.CHARGING_STATIONS, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.CHARGING_STATION, action: Action.READ, attributes: ['*'] },

MODIFY
src/authorization/DynamicAuthorizationFactory.ts
src/authorization/DynamicAuthorizationFactory.ts
@@ -2,6 +2,8 @@ import { DynamicAuthorizationDataSourceData, DynamicAuthorizationDataSourceName,
import AssignedSitesCompaniesDynamicAuthorizationDataSource from './dynamic-data-source/AssignedSitesCompaniesDynamicAuthorizationDataSource';
import AssignedSitesCompaniesDynamicAuthorizationFilter from './dynamic-filters/AssignedSitesCompaniesDynamicAuthorizationFilter';
+import AssignedSitesDynamicAuthorizationDataSource from './dynamic-data-source/AssignedSitesDynamicAuthorizationDataSource';
+import AssignedSitesDynamicAuthorizationFilter from './dynamic-filters/AssignedSitesDynamicAuthorizationFilter';
import DynamicAuthorizationDataSource from './DynamicAuthorizationDataSource';
import DynamicAuthorizationFilter from './DynamicAuthorizationFilter';
import Tenant from '../types/Tenant';
@@ -16,6 +18,10 @@ export default class DynamicAuthorizationFactory {
switch (filter) {
case DynamicAuthorizationFilterName.ASSIGNED_SITES_COMPANIES:
dynamicFilter = new AssignedSitesCompaniesDynamicAuthorizationFilter(tenant, userToken);
+ break;
+ case DynamicAuthorizationFilterName.ASSIGNED_SITES:
+ dynamicFilter = new AssignedSitesDynamicAuthorizationFilter(tenant, userToken);
+ break;
}
// Init Data Source
if (dynamicFilter) {
@@ -50,6 +56,8 @@ export default class DynamicAuthorizationFactory {
switch (dataSource) {
case DynamicAuthorizationDataSourceName.ASSIGNED_SITES_COMPANIES:
return new AssignedSitesCompaniesDynamicAuthorizationDataSource(tenant, user);
+ case DynamicAuthorizationDataSourceName.ASSIGNED_SITES:
+ return new AssignedSitesDynamicAuthorizationDataSource(tenant, user);
}
}
}

ADD
src/authorization/dynamic-data-source/AssignedSitesDynamicAuthorizationDataSource.ts
+import { AssignedSitesDynamicAuthorizationDataSourceData, DynamicAuthorizationDataSourceName } from '../../types/Authorization';
+
+import Constants from '../../utils/Constants';
+import DynamicAuthorizationDataSource from '../DynamicAuthorizationDataSource';
+import SiteStorage from '../../storage/mongodb/SiteStorage';
+import _ from 'lodash';
+
+export default class AssignedSitesDynamicAuthorizationDataSource
+ extends DynamicAuthorizationDataSource<AssignedSitesDynamicAuthorizationDataSourceData> {
+
+ public getName(): DynamicAuthorizationDataSourceName {
+ return DynamicAuthorizationDataSourceName.ASSIGNED_SITES;
+ }
+
+ public async loadData(): Promise<void> {
+ const assignedSitesCompaniesData: AssignedSitesDynamicAuthorizationDataSourceData = {};
+ // Get Site IDs from Site Admin flag
+ assignedSitesCompaniesData.siteIDs = await this.getAssignedSiteIDs();
+ // Set
+ this.setData(assignedSitesCompaniesData);
+ }
+
+ private async getAssignedSiteIDs(): Promise<string[]> {
+ // Get the Site IDs of the assigned Sites
+ const sites = await SiteStorage.getSites(this.tenant.id,
+ {
+ userID: this.userToken.id,
+ issuer: true,
+ }, Constants.DB_PARAMS_MAX_LIMIT,
+ ['id']
+ );
+ return _.uniq(_.map(sites.result, 'id'));
+ }
+}

ADD
src/authorization/dynamic-filters/AssignedSitesDynamicAuthorizationFilter.ts
+import { AuthorizationFilter, DynamicAuthorizationDataSourceName, Entity } from '../../types/Authorization';
+
+import AssignedSitesDynamicAuthorizationDataSource from '../dynamic-data-source/AssignedSitesDynamicAuthorizationDataSource';
+import DynamicAuthorizationFilter from '../DynamicAuthorizationFilter';
+import Utils from '../../utils/Utils';
+
+export default class AssignedSitesDynamicAuthorizationFilter extends DynamicAuthorizationFilter {
+ public processFilter(authorizationFilters: AuthorizationFilter, extraFilters: Record<string, any>): void {
+ // Get Site IDs
+ const assignedSitesDataSource = this.getDataSource(
+ DynamicAuthorizationDataSourceName.ASSIGNED_SITES) as AssignedSitesDynamicAuthorizationDataSource;
+ const { siteIDs } = assignedSitesDataSource.getData();
+ // Check
+ if (!Utils.isEmptyArray(siteIDs)) {
+ // Force the filter
+ authorizationFilters.filters.siteIDs = siteIDs;
+ // Check if filter is provided
+ if (Utils.objectHasProperty(extraFilters, 'SiteID') &&
+ !Utils.isNullOrUndefined(extraFilters['SiteID'])) {
+ const filteredSiteIDs: string[] = extraFilters['SiteID'].split('|');
+ // Override
+ authorizationFilters.filters.siteIDs = filteredSiteIDs.filter(
+ (siteID) => authorizationFilters.filters.siteIDs.includes(siteID));
+ }
+ }
+ if (!Utils.isEmptyArray(authorizationFilters.filters.siteIDs)) {
+ authorizationFilters.authorized = true;
+ }
+ }
+
+ public getApplicableEntities(): Entity[] {
+ return [
+ Entity.SITES
+ ];
+ }
+
+ public getApplicableDataSources(): DynamicAuthorizationDataSourceName[] {
+ return [
+ DynamicAuthorizationDataSourceName.ASSIGNED_SITES
+ ];
+ }
+}

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
@@ -571,65 +571,38 @@ export default class AuthorizationService {
const authorizationFilters: AuthorizationFilter = {
filters: {},
dataSources: new Map(),
- projectFields: [
- 'id', 'name', 'siteID', 'maximumPower', 'voltage', 'numberOfPhases', 'accessControl', 'smartCharging', 'address',
- 'site.id', 'site.name', 'issuer', 'distanceMeters', 'createdOn', 'createdBy', 'lastChangedOn', 'lastChangedBy'
- ],
- authorized: userToken.role === UserRole.ADMIN,
+ projectFields: [ ],
+ authorized: false,
};
- // Filter projected fields
- authorizationFilters.projectFields = AuthorizationService.filterProjectFields(
- authorizationFilters.projectFields, filteredRequest.ProjectFields);
- // Not an Admin?
- if (userToken.role !== UserRole.ADMIN) {
- // Get assigned SiteArea IDs
- const siteAreaIDs = await AuthorizationService.getAssignedSiteAreaIDs(tenant.id, userToken);
- if (!Utils.isEmptyArray(siteAreaIDs)) {
- // Force the filter
- authorizationFilters.filters.siteAreaIDs = siteAreaIDs;
- // Check if filter is provided
- if (Utils.objectHasProperty(filteredRequest, 'SiteAreaID') &&
- !Utils.isNullOrUndefined(filteredRequest['SiteAreaID'])) {
- const filteredSiteAreaIDs: string[] = filteredRequest['SiteAreaID'].split('|');
- // Override
- authorizationFilters.filters.siteAreaIDs = filteredSiteAreaIDs.filter(
- (siteAreaID) => authorizationFilters.filters.siteAreaIDs.includes(siteAreaID));
- }
- }
- if (!Utils.isEmptyArray(authorizationFilters.filters.siteAreaIDs)) {
- authorizationFilters.authorized = true;
- }
- }
-
+ // Check static & dynamic authorization
+ await this.canPerformAuthorizationAction(
+ tenant, userToken, Entity.SITE_AREAS, Action.LIST, authorizationFilters, filteredRequest);
return authorizationFilters;
}
- public static async addSiteAreasAuthorizations(tenant: Tenant, userToken: UserToken, siteAreas: SiteAreaDataResult): Promise<void> {
- // Get Site Admins
- const siteAdminIDs = await AuthorizationService.getSiteAdminSiteIDs(tenant.id, userToken);
+ public static async addSiteAreasAuthorizations(tenant: Tenant, userToken: UserToken, siteAreas: SiteAreaDataResult, authorizationFilter: AuthorizationFilter,
+ filteredRequest: Record<string, any>): Promise<void> {
// Add canCreate flag to root
- siteAreas.canCreate = await Authorizations.canCreateSite(userToken);
+ siteAreas.canCreate = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.SITE_AREAS, Action.CREATE, authorizationFilter);
+
// Enrich
for (const siteArea of siteAreas.result) {
- await AuthorizationService.addSiteAreaAuthorizations(tenant, userToken, siteArea, siteAdminIDs);
+ await AuthorizationService.addSiteAreaAuthorizations(tenant, userToken, siteArea, authorizationFilter, filteredRequest);
}
}
- public static async addSiteAreaAuthorizations(tenant: Tenant, userToken: UserToken, siteArea: SiteArea, siteAdminIDs?: string[]): Promise<void> {
- // Get Site Admins
- if (Utils.isEmptyArray(siteAdminIDs)) {
- siteAdminIDs = await AuthorizationService.getSiteAdminSiteIDs(tenant.id, userToken);
- }
+ public static async addSiteAreaAuthorizations(tenant: Tenant, userToken: UserToken, siteArea: SiteArea, authorizationFilter: AuthorizationFilter,
+ filteredRequest: Record<string, any>): Promise<void> {
// Enrich
if (!siteArea.issuer) {
siteArea.canRead = true;
siteArea.canUpdate = false;
siteArea.canDelete = false;
} else {
- const isSiteAdmin = siteAdminIDs.includes(siteArea.siteID) || (userToken.role === UserRole.ADMIN);
- siteArea.canRead = await Authorizations.canReadSiteArea(userToken);
- siteArea.canUpdate = await Authorizations.canUpdateSiteArea(userToken) && isSiteAdmin;
- siteArea.canDelete = await Authorizations.canDeleteSiteArea(userToken) && isSiteAdmin;
+ // todo: add id?
+ siteArea.canRead = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.SITE_AREA, Action.READ, authorizationFilter, filteredRequest);
+ siteArea.canUpdate = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.SITE_AREA, Action.DELETE, authorizationFilter, filteredRequest);
+ siteArea.canDelete = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.SITE_AREA, Action.UPDATE, authorizationFilter, filteredRequest);
}
}
@@ -891,7 +864,7 @@ export default class AuthorizationService {
return false;
}
// Check Dynamic Auth
- await AuthorizationService.processDynamicFilters(tenant, userToken, Action.LIST, Entity.COMPANIES,
+ await AuthorizationService.processDynamicFilters(tenant, userToken, action, entity,
authorizationFilters, authorizationContext, filteredRequest);
// Filter projected fields
authorizationFilters.projectFields = AuthorizationService.filterProjectFields(

MODIFY
src/server/rest/v1/service/SiteAreaService.ts
src/server/rest/v1/service/SiteAreaService.ts
@@ -8,7 +8,6 @@ import AppError from '../../../../exception/AppError';
import AuthorizationService from './AuthorizationService';
import Authorizations from '../../../../authorization/Authorizations';
import { ChargingProfilePurposeType } from '../../../../types/ChargingProfile';
-import ChargingStationStorage from '../../../../storage/mongodb/ChargingStationStorage';
import Constants from '../../../../utils/Constants';
import ConsumptionStorage from '../../../../storage/mongodb/ConsumptionStorage';
import LockingHelper from '../../../../locking/LockingHelper';
@@ -214,21 +213,12 @@ export default class SiteAreaService {
// Check if component is active
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.ORGANIZATION,
Action.LIST, Entity.SITE_AREAS, MODULE_NAME, 'handleGetSiteAreas');
- // Check static auth
- if (!await Authorizations.canListSiteAreas(req.user)) {
- throw new AppAuthError({
- errorCode: HTTPAuthError.FORBIDDEN,
- user: req.user,
- action: Action.LIST, entity: Entity.SITE_AREAS,
- module: MODULE_NAME, method: 'handleGetSiteAreas'
- });
- }
// Filter
const filteredRequest = SiteAreaSecurity.filterSiteAreasRequest(req.query);
// Check dynamic auth
- const readSiteAreasAuthorizationFilters = await AuthorizationService.checkAndGetSiteAreasAuthorizationFilters(
+ const authorizationSiteAreasFilter = await AuthorizationService.checkAndGetSiteAreasAuthorizationFilters(
req.tenant, req.user, filteredRequest);
- // Get the sites
+ // Get the SiteAreas
const siteAreas = await SiteAreaStorage.getSiteAreas(req.user.tenantID,
{
issuer: filteredRequest.Issuer,
@@ -239,7 +229,7 @@ export default class SiteAreaService {
siteIDs: filteredRequest.SiteID ? filteredRequest.SiteID.split('|') : null,
locCoordinates: filteredRequest.LocCoordinates,
locMaxDistanceMeters: filteredRequest.LocMaxDistanceMeters,
- ...readSiteAreasAuthorizationFilters.filters
+ ...authorizationSiteAreasFilter.filters
},
{
limit: filteredRequest.Limit,
@@ -247,11 +237,11 @@ export default class SiteAreaService {
sort: filteredRequest.SortFields,
onlyRecordCount: filteredRequest.OnlyRecordCount
},
- readSiteAreasAuthorizationFilters.projectFields
+ authorizationSiteAreasFilter.projectFields
);
// Add Auth flags
await AuthorizationService.addSiteAreasAuthorizations(
- req.tenant, req.user, siteAreas as SiteAreaDataResult);
+ req.tenant, req.user, siteAreas as SiteAreaDataResult,authorizationSiteAreasFilter, filteredRequest);
// Return
res.json(siteAreas);
next();

MODIFY
src/types/Authorization.ts
src/types/Authorization.ts
@@ -177,10 +177,12 @@ export interface AuthorizationActions {
export enum DynamicAuthorizationFilterName {
ASSIGNED_SITES_COMPANIES = 'AssignedSitesCompanies',
+ ASSIGNED_SITES = 'AssignedSites',
}
export enum DynamicAuthorizationDataSourceName {
ASSIGNED_SITES_COMPANIES = 'AssignedSitesCompanies',
+ ASSIGNED_SITES = 'AssignedSites',
}
export interface DynamicAuthorizationDataSourceData {}
@@ -188,3 +190,7 @@ export interface DynamicAuthorizationDataSourceData {}
export interface AssignedSitesCompaniesDynamicAuthorizationDataSourceData extends DynamicAuthorizationDataSourceData {
companyIDs?: string[];
}
+
+export interface AssignedSitesDynamicAuthorizationDataSourceData extends DynamicAuthorizationDataSourceData {
+ siteIDs?: string[];
+}

Change getSiteAreas logic.