Align and refactor authorization for ABAC
Add auth information in Get requests for GUI migration
Add missing filters / auth in backend that exist in GUI
Align and fix auth definition for assets
Differentiate auth check on action and resource
Refactoring when possible
MODIFY
src/authorization/Authorizations.ts
src/authorization/Authorizations.ts
@@ -681,6 +681,10 @@ export default class Authorizations {
return Authorizations.canPerformAction(loggedUser, Entity.ASSET, Action.RETRIEVE_CONSUMPTION);
}
+ public static async canReadAssetConsumption(loggedUser: UserToken): Promise<boolean> {
+ return Authorizations.canPerformAction(loggedUser, Entity.ASSET, Action.READ_CONSUMPTION);
+ }
+
public static async canCreateAssetConsumption(loggedUser: UserToken): Promise<boolean> {
return Authorizations.canPerformAction(loggedUser, Entity.ASSET, Action.CREATE_CONSUMPTION);
}

MODIFY
src/authorization/AuthorizationsDefinition.ts
src/authorization/AuthorizationsDefinition.ts
@@ -302,7 +302,8 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
]
},
{ resource: Entity.PRICING, action: [Action.READ, Action.UPDATE] },
- { resource: Entity.PRICING_DEFINITION, action: [Action.LIST],
+ {
+ resource: Entity.PRICING_DEFINITION, action: [Action.LIST],
attributes: [
'id', 'entityID', 'entityType', 'name', 'description', 'entityName',
'staticRestrictions.validFrom', 'staticRestrictions.validTo', 'staticRestrictions.connectorType', 'staticRestrictions.connectorPowerkW',
@@ -314,7 +315,8 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
'dimensions.parkingTime.active', 'dimensions.parkingTime.price', 'dimensions.parkingTime.stepSize', 'dimensions.parkingTime.pricedData',
]
},
- { resource: Entity.PRICING_DEFINITION, action: [Action.CREATE, Action.READ, Action.UPDATE, Action.DELETE],
+ {
+ resource: Entity.PRICING_DEFINITION, action: [Action.CREATE, Action.READ, Action.UPDATE, Action.DELETE],
attributes: [
'id', 'entityID', 'entityType', 'name', 'description', 'entityName',
'staticRestrictions.validFrom', 'staticRestrictions.validTo', 'staticRestrictions.connectorType', 'staticRestrictions.connectorPowerkW',
@@ -337,7 +339,27 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
{ resource: Entity.INVOICE, action: [Action.DOWNLOAD, Action.READ] },
{
resource: Entity.ASSET, action: [Action.CREATE, Action.READ,
- Action.CHECK_CONNECTION, Action.RETRIEVE_CONSUMPTION, Action.CREATE_CONSUMPTION]
+ Action.CHECK_CONNECTION, Action.CREATE_CONSUMPTION]
+ },
+ {
+ resource: Entity.ASSET, action: Action.READ_CONSUMPTION,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['DynamicAsset']
+ }
+ }
+ },
+ {
+ resource: Entity.ASSET, action: Action.RETRIEVE_CONSUMPTION,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['DynamicAsset', '-UsesPushAPI']
+ }
+ }
},
{
resource: Entity.ASSET, action: [Action.UPDATE, Action.DELETE],
@@ -797,6 +819,16 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
]
},
{ resource: Entity.ASSET, action: Action.READ },
+ {
+ resource: Entity.ASSET, action: Action.READ_CONSUMPTION,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['DynamicAsset']
+ }
+ }
+ },
{ resource: Entity.SETTING, action: Action.READ },
{
resource: Entity.CAR_CATALOG, action: Action.LIST,
@@ -1057,6 +1089,20 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
'dynamicAsset', 'connectionID', 'meterID', 'currentInstantWatts', 'currentStateOfCharge'
],
},
+ {
+ resource: Entity.ASSET, action: Action.READ_CONSUMPTION,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['DynamicAsset']
+ }
+ },
+ attributes: [
+ 'id', 'name', 'siteAreaID', 'siteArea.id', 'siteArea.name', 'siteArea.siteID', 'siteID', 'assetType', 'coordinates',
+ 'dynamicAsset', 'connectionID', 'meterID', 'currentInstantWatts', 'currentStateOfCharge'
+ ],
+ },
{
resource: Entity.CAR, action: Action.LIST,
condition: {
@@ -1074,7 +1120,8 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
'user.id', 'user.name', 'user.firstName', 'userID'
],
},
- { resource: Entity.CAR, action: Action.CREATE,
+ {
+ resource: Entity.CAR, action: Action.CREATE,
condition: {
Fn: 'custom:dynamicAuthorizations',
args: {
@@ -1290,7 +1337,8 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
}
}
},
- { resource: Entity.PRICING_DEFINITION, action: Action.LIST,
+ {
+ resource: Entity.PRICING_DEFINITION, action: Action.LIST,
attributes: ['id', 'entityID', 'entityType', 'name', 'description', 'entityName',
'staticRestrictions.validFrom', 'staticRestrictions.validTo', 'staticRestrictions.connectorType', 'staticRestrictions.connectorPowerkW',
'restrictions.daysOfWeek', 'restrictions.timeFrom', 'restrictions.timeTo',
@@ -1308,7 +1356,8 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
}
},
},
- { resource: Entity.PRICING_DEFINITION, action: [Action.CREATE, Action.READ, Action.UPDATE, Action.DELETE],
+ {
+ resource: Entity.PRICING_DEFINITION, action: [Action.CREATE, Action.READ, Action.UPDATE, Action.DELETE],
attributes: ['id', 'entityID', 'entityType', 'name', 'description', 'entityName',
'staticRestrictions.validFrom', 'staticRestrictions.validTo', 'staticRestrictions.connectorType', 'staticRestrictions.connectorPowerkW',
'restrictions.daysOfWeek', 'restrictions.timeFrom', 'restrictions.timeTo',

MODIFY
src/authorization/DynamicAuthorizationFactory.ts
src/authorization/DynamicAuthorizationFactory.ts
@@ -5,6 +5,7 @@ import AssignedSitesCompaniesDynamicAuthorizationFilter from './dynamic-filters/
import AssignedSitesDynamicAuthorizationDataSource from './dynamic-data-source/AssignedSitesDynamicAuthorizationDataSource';
import AssignedSitesDynamicAuthorizationFilter from './dynamic-filters/AssignedSitesDynamicAuthorizationFilter';
import BasicUserDynamicAuthorizationAssert from './dynamic-assert/BasicUserDynamicAuthorizationAssert';
+import DynamicAssetDynamicAuthorizationFilter from './dynamic-filters/DynamicAssetDynamicAuthorizationFilter';
import DynamicAuthorizationAssert from './DynamicAuthorizationAssert';
import DynamicAuthorizationDataSource from './DynamicAuthorizationDataSource';
import DynamicAuthorizationFilter from './DynamicAuthorizationFilter';
@@ -23,6 +24,7 @@ import SitesOwnerDynamicAuthorizationFilter from './dynamic-filters/SitesOwnerDy
import Tenant from '../types/Tenant';
import UserMandatoryDynamicAuthorizationAssert from './dynamic-assert/UserMandatoryDynamicAuthorizationAssert';
import UserToken from '../types/UserToken';
+import UsesPushAPIDynamicAuthorizationFilter from './dynamic-filters/UsesPushAPIDynamicAuthorizationFilter';
export default class DynamicAuthorizationFactory {
public static async getDynamicFilter(tenant: Tenant, userToken: UserToken,
@@ -59,6 +61,12 @@ export default class DynamicAuthorizationFactory {
case DynamicAuthorizationFilterName.LOCAL_ISSUER:
dynamicFilter = new LocalIssuerDynamicAuthorizationFilter(tenant, userToken, negateFilter);
break;
+ case DynamicAuthorizationFilterName.DYNAMIC_ASSET:
+ dynamicFilter = new DynamicAssetDynamicAuthorizationFilter(tenant, userToken, negateFilter);
+ break;
+ case DynamicAuthorizationFilterName.USES_PUSH_API:
+ dynamicFilter = new UsesPushAPIDynamicAuthorizationFilter(tenant, userToken, negateFilter);
+ break;
}
// Init Data Source
if (dynamicFilter) {

ADD
src/authorization/dynamic-filters/DynamicAssetDynamicAuthorizationFilter.ts
+import { AuthorizationFilter, DynamicAuthorizationDataSourceName, Entity } from '../../types/Authorization';
+
+import DynamicAuthorizationFilter from '../DynamicAuthorizationFilter';
+import { EntityData } from '../../types/GlobalType';
+import Utils from '../../utils/Utils';
+
+export default class DynamicAssetDynamicAuthorizationFilter extends DynamicAuthorizationFilter {
+ public processFilter(authorizationFilters: AuthorizationFilter, extraFilters: Record<string, any>, entityData?: EntityData): void {
+ authorizationFilters.authorized = true;
+ if (Utils.objectHasProperty(entityData, 'dynamicAsset')) {
+ // Dynamic asset has true value
+ authorizationFilters.authorized = entityData['dynamicAsset'];
+ }
+ }
+
+ public getApplicableEntities(): Entity[] {
+ return [
+ Entity.ASSET
+ ];
+ }
+
+ public getApplicableDataSources(): DynamicAuthorizationDataSourceName[] {
+ return [];
+ }
+}

ADD
src/authorization/dynamic-filters/UsesPushAPIDynamicAuthorizationFilter.ts
+import { AuthorizationFilter, DynamicAuthorizationDataSourceName, Entity } from '../../types/Authorization';
+
+import DynamicAuthorizationFilter from '../DynamicAuthorizationFilter';
+import { EntityData } from '../../types/GlobalType';
+import Utils from '../../utils/Utils';
+
+export default class UsesPushAPIDynamicAuthorizationFilter extends DynamicAuthorizationFilter {
+ public processFilter(authorizationFilters: AuthorizationFilter, extraFilters: Record<string, any>, entityData?: EntityData): void {
+ authorizationFilters.authorized = true;
+ if (Utils.objectHasProperty(entityData, 'usesPushAPI')) {
+ // usesPushAPI has true value
+ authorizationFilters.authorized = entityData['usesPushAPI'];
+ }
+ }
+
+ public getApplicableEntities(): Entity[] {
+ return [
+ Entity.ASSET
+ ];
+ }
+
+ public getApplicableDataSources(): DynamicAuthorizationDataSourceName[] {
+ return [];
+ }
+}

MODIFY
src/server/rest/v1/service/AssetService.ts
src/server/rest/v1/service/AssetService.ts
@@ -4,6 +4,7 @@ import Tenant, { TenantComponents } from '../../../../types/Tenant';
import AppError from '../../../../exception/AppError';
import Asset from '../../../../types/Asset';
+import { AssetDataResult } from '../../../../types/DataResult';
import AssetFactory from '../../../../integration/asset/AssetFactory';
import { AssetInErrorType } from '../../../../types/InError';
import AssetStorage from '../../../../storage/mongodb/AssetStorage';
@@ -30,18 +31,19 @@ export default class AssetService {
public static async handleGetAssetConsumption(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Check if component is active
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.ASSET,
- Action.READ, Entity.ASSET, MODULE_NAME, 'handleGetAssetConsumption');
+ Action.READ_CONSUMPTION, Entity.ASSET, MODULE_NAME, 'handleGetAssetConsumption');
// Filter
const filteredRequest = AssetValidator.getInstance().validateAssetGetConsumptionsReq(req.query);
UtilsService.assertIdIsProvided(action, filteredRequest.AssetID, MODULE_NAME,
'handleGetAssetConsumption', req.user);
- // Check dynamic auth
- const authorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.READ, {});
+ // Check action authorization before querying storage
+ const staticAuthorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.READ_CONSUMPTION, {});
// Get asset
- const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.AssetID, {}, authorizationAssetFilter);
+ const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.AssetID, { dynamicOnly: true }, staticAuthorizationAssetFilter);
UtilsService.assertObjectExists(action, asset, `Asset ID '${filteredRequest.AssetID}' cannot be retrieved`,
MODULE_NAME, 'handleGetAssetConsumption', req.user);
-
+ // Check dynamic auth
+ await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.READ_CONSUMPTION, {}, asset);
// Check dates
if (!filteredRequest.StartDate || !filteredRequest.EndDate) {
throw new AppError({
@@ -83,12 +85,14 @@ export default class AssetService {
const filteredRequest = AssetValidator.getInstance().validateAssetConsumptionCreateReq({ ...req.query, ...req.body });
UtilsService.assertIdIsProvided(action, filteredRequest.assetID, MODULE_NAME,
'handleCreateAssetConsumption', req.user);
- // Check dynamic auth
- const authorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.CREATE_CONSUMPTION, {});
+ // Check static auth before querying storage
+ const staticAuthorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.CREATE_CONSUMPTION, {});
// Get Asset
- const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.assetID, { withSiteArea: true }, authorizationAssetFilter);
+ const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.assetID, { withSiteArea: true }, staticAuthorizationAssetFilter);
UtilsService.assertObjectExists(action, asset, `Asset ID '${filteredRequest.assetID}' cannot be retrieved to create consumption`,
MODULE_NAME, 'handleCreateAssetConsumption', req.user);
+ // Check dynamic auth
+ await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.CREATE_CONSUMPTION, {}, asset);
// Check if connection ID exists
if (!Utils.isNullOrUndefined(asset.connectionID)) {
throw new AppError({
@@ -165,7 +169,6 @@ export default class AssetService {
next();
}
-
public static async handleCheckAssetConnection(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Check if component is active
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.ASSET,
@@ -214,13 +217,15 @@ export default class AssetService {
// Filter request
const assetID = AssetValidator.getInstance().validateAssetGetReq(req.query).ID;
UtilsService.assertIdIsProvided(action, assetID, MODULE_NAME, 'handleRetrieveConsumption', req.user);
- // Check dynamic auth
- const authorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(
+ // Check static auth before querying storage
+ const staticAuthorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(
req.tenant, req.user, Action.RETRIEVE_CONSUMPTION, {});
// Get
- const asset = await AssetService.getAssetFromStorage(req.tenant, assetID, { dynamicOnly: true, usesPushAPI: false }, authorizationAssetFilter);
+ const asset = await AssetService.getAssetFromStorage(req.tenant, assetID, { dynamicOnly: true, usesPushAPI: false }, staticAuthorizationAssetFilter);
UtilsService.assertObjectExists(action, asset, `Asset ID '${assetID}' consumption cannot be retrieved`,
MODULE_NAME, 'handleRetrieveConsumption', req.user);
+ // Dynamic auth
+ await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.RETRIEVE_CONSUMPTION, {}, asset);
// Get asset factory
const assetImpl = await AssetFactory.getAssetImpl(req.tenant, asset.connectionID);
if (!assetImpl) {
@@ -289,6 +294,9 @@ export default class AssetService {
},
authorizationAssetsInErrorFilter.projectFields
);
+ // Add Auth flags
+ await AuthorizationService.addAssetsAuthorizations(
+ req.tenant, req.user, assets as AssetDataResult, authorizationAssetsInErrorFilter);
res.json(assets);
next();
}
@@ -301,13 +309,15 @@ export default class AssetService {
const filteredRequest = AssetValidator.getInstance().validateAssetGetReq(req.query);
// Check Mandatory fields
UtilsService.assertIdIsProvided(action, filteredRequest.ID, MODULE_NAME, 'handleDeleteAsset', req.user);
- // Check dynamic auth
- const authorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(
+ // Check static auth before querying storage
+ const staticAuthorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(
req.tenant, req.user, Action.DELETE, filteredRequest);
// Get
- const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.ID, { withSiteArea: filteredRequest.WithSiteArea }, authorizationAssetFilter);
+ const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.ID, { withSiteArea: filteredRequest.WithSiteArea }, staticAuthorizationAssetFilter);
UtilsService.assertObjectExists(action, asset, `Asset ID '${filteredRequest.ID}' cannot be deleted`,
MODULE_NAME, 'handleDeleteAsset', req.user);
+ // Dynamic auth
+ await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.DELETE, filteredRequest, asset);
// Delete
await AssetStorage.deleteAsset(req.tenant, asset.id);
// Log
@@ -331,13 +341,15 @@ export default class AssetService {
const filteredRequest = AssetValidator.getInstance().validateAssetGetReq(req.query);
// ID is mandatory
UtilsService.assertIdIsProvided(action, filteredRequest.ID, MODULE_NAME, 'handleGetAsset', req.user);
- // Check dynamic auth
- const authorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(
+ // Check action authorization before querying storage
+ const staticAuthorizationAssetFilter = await AuthorizationService.checkAndGetAssetAuthorizations(
req.tenant, req.user, Action.READ, filteredRequest);
// Get it
- const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.ID, { withSiteArea: filteredRequest.WithSiteArea }, authorizationAssetFilter);
+ const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.ID, { withSiteArea: filteredRequest.WithSiteArea }, staticAuthorizationAssetFilter);
UtilsService.assertObjectExists(action, asset, `Asset ID '${filteredRequest.ID}' does not exist`,
MODULE_NAME, 'handleGetAsset', req.user);
+ // Dynamic auth
+ await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.READ, filteredRequest, asset);
res.json(asset);
next();
}
@@ -396,6 +408,9 @@ export default class AssetService {
},
authorizationAssetsFilter.projectFields
);
+ // Add Auth flags
+ await AuthorizationService.addAssetsAuthorizations(
+ req.tenant, req.user, assets as AssetDataResult, authorizationAssetsFilter);
res.json(assets);
next();
}
@@ -445,9 +460,8 @@ export default class AssetService {
// Filter
const filteredRequest = AssetValidator.getInstance().validateAssetUpdateReq(req.body);
UtilsService.checkIfAssetValid(filteredRequest, req);
- // Get dynamic auth
- const authorizationFilter = await AuthorizationService.checkAndGetAssetAuthorizations(
- req.tenant, req.user, Action.UPDATE, {}, filteredRequest);
+ // Check action authorization before querying storage
+ const staticAuthorizationFilter = await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.UPDATE, {}, filteredRequest);
// Check Site Area authorization
let siteArea: SiteArea = null;
if (Utils.isComponentActiveFromToken(req.user, TenantComponents.ORGANIZATION) && filteredRequest.siteAreaID) {
@@ -455,9 +469,11 @@ export default class AssetService {
req.tenant, req.user, filteredRequest.siteAreaID, Action.UPDATE, action, filteredRequest, null, false);
}
// Get asset
- const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.id, {}, authorizationFilter);
+ const asset = await AssetService.getAssetFromStorage(req.tenant, filteredRequest.id, {}, staticAuthorizationFilter);
UtilsService.assertObjectExists(action, asset, `Asset ID '${filteredRequest.id}' cannot be modified`,
MODULE_NAME, 'handleUpdateAsset', req.user);
+ // Check dynamic auth
+ await AuthorizationService.checkAndGetAssetAuthorizations(req.tenant, req.user, Action.UPDATE, {}, asset);
// Update Asset values and persist
asset.name = filteredRequest.name;
asset.siteAreaID = filteredRequest.siteAreaID;

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
import { Action, AuthorizationActions, AuthorizationContext, AuthorizationFilter, Entity } from '../../../../types/Authorization';
+import { AssetDataResult, CarCatalogDataResult, CarDataResult, CompanyDataResult, LogDataResult, PricingDefinitionDataResult, RegistrationTokenDataResult, SiteAreaDataResult, SiteDataResult, TagDataResult, UserDataResult } from '../../../../types/DataResult';
import { Car, CarCatalog } from '../../../../types/Car';
-import { CarCatalogDataResult, CarDataResult, CompanyDataResult, LogDataResult, PricingDefinitionDataResult, RegistrationTokenDataResult, SiteAreaDataResult, SiteDataResult, TagDataResult, UserDataResult } from '../../../../types/DataResult';
import { HttpCarCatalogRequest, HttpCarCatalogsRequest, HttpCarRequest, HttpCarsRequest } from '../../../../types/requests/HttpCarRequest';
import { HttpChargingStationRequest, HttpChargingStationsRequest } from '../../../../types/requests/HttpChargingStationRequest';
import { HttpCompaniesRequest, HttpCompanyRequest } from '../../../../types/requests/HttpCompanyRequest';
@@ -14,6 +14,7 @@ import Tenant, { TenantComponents } from '../../../../types/Tenant';
import User, { UserRole } from '../../../../types/User';
import AppAuthError from '../../../../exception/AppAuthError';
+import Asset from '../../../../types/Asset';
import AssetStorage from '../../../../storage/mongodb/AssetStorage';
import Authorizations from '../../../../authorization/Authorizations';
import Company from '../../../../types/Company';
@@ -277,6 +278,29 @@ export default class AuthorizationService {
return authorizationFilters;
}
+ public static async addAssetsAuthorizations(tenant: Tenant, userToken: UserToken, assets: AssetDataResult, authorizationFilter: AuthorizationFilter): Promise<void> {
+ // Add Meta Data
+ assets.metadata = authorizationFilter.metadata;
+ // Add Authorizations
+ assets.canCreate = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.ASSET, Action.CREATE, authorizationFilter);
+ for (const asset of assets.result) {
+ await AuthorizationService.addAssetAuthorizations(tenant, userToken, asset, authorizationFilter);
+ }
+ }
+
+ public static async addAssetAuthorizations(tenant: Tenant, userToken: UserToken, asset: Asset, authorizationFilter: AuthorizationFilter): Promise<void> {
+ asset.canRead = true; // Always true as it should be filtered upfront
+ asset.canDelete = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.ASSET, Action.DELETE, authorizationFilter, {}, asset);
+ asset.canUpdate = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.ASSET, Action.UPDATE, authorizationFilter, {}, asset);
+ asset.canRetrieveConsumption = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.ASSET, Action.RETRIEVE_CONSUMPTION, authorizationFilter, {}, asset);
+ asset.canReadConsumption = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.ASSET, Action.READ_CONSUMPTION, authorizationFilter, {}, asset);
+ // Not used in dashboard
+ // asset.canCreateConsumption = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.ASSET, Action.CREATE_CONSUMPTION, authorizationFilter, {}, asset);
+ asset.canCheckConnection = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.ASSET, Action.CHECK_CONNECTION, authorizationFilter, {}, asset);
+ // Optimize data over the net
+ Utils.removeCanPropertiesWithFalseValue(asset);
+ }
+
public static async checkAndGetUserAuthorizations(tenant: Tenant, userToken: UserToken,
filteredRequest: Partial<HttpUserRequest>, authAction: Action, entityData?: EntityData): Promise<AuthorizationFilter> {
return AuthorizationService.checkAndGetEntityAuthorizations(

MODIFY
src/types/Asset.ts
src/types/Asset.ts
import Consumption, { AbstractCurrentConsumption } from './Consumption';
+import { AssetAuthorizationActions } from './Authorization';
import CreatedUpdatedProps from './CreatedUpdatedProps';
import SiteArea from './SiteArea';
-export default interface Asset extends CreatedUpdatedProps, AbstractCurrentConsumption {
+export default interface Asset extends CreatedUpdatedProps, AbstractCurrentConsumption, AssetAuthorizationActions {
id: string;
name: string;
siteAreaID: string;

MODIFY
src/types/Authorization.ts
src/types/Authorization.ts
@@ -138,6 +138,7 @@ export enum Action {
CHECK_CONNECTION = 'CheckConnection',
CLEAR_BILLING_TEST_DATA = 'ClearBillingTestData',
RETRIEVE_CONSUMPTION = 'RetrieveConsumption',
+ READ_CONSUMPTION = 'ReadConsumption',
CREATE_CONSUMPTION = 'CreateConsumption',
PING = 'Ping',
GENERATE_LOCAL_TOKEN = 'GenerateLocalToken',
@@ -196,6 +197,13 @@ export interface RegistrationTokenAuthorizationActions extends AuthorizationActi
canRevoke?: boolean;
}
+export interface AssetAuthorizationActions extends AuthorizationActions {
+ canRetrieveConsumption?:boolean;
+ canReadConsumption?:boolean;
+ canCreateConsumption?:boolean;
+ canCheckConnection?:boolean;
+}
+
export interface SiteAreaAuthorizationActions extends AuthorizationActions {
canAssignAssets?: boolean;
canUnassignAssets?: boolean;
@@ -224,6 +232,8 @@ export enum DynamicAuthorizationFilterName {
OWN_USER = 'OwnUser',
LOCAL_ISSUER = 'LocalIssuer',
EXCLUDE_ACTION = 'ExcludeAction',
+ DYNAMIC_ASSET = 'DynamicAsset',
+ USES_PUSH_API = 'UsesPushAPI'
}
export enum DynamicAuthorizationAssertName {

MODIFY
src/types/DataResult.ts
src/types/DataResult.ts
import { Car, CarCatalog } from './Car';
import Transaction, { TransactionStats } from './Transaction';
+import Asset from './Asset';
import { AuthorizationDefinitionFieldMetadata } from './Authorization';
import Company from './Company';
import { Log } from './Log';
@@ -92,3 +93,7 @@ export interface TransactionRefundDataResult {
currency: string;
};
}
+
+export interface AssetDataResult extends DataResult<Asset> {
+ canCreate: boolean;
+}

Align and refactor authorization for ABAC

- Add auth information in Get requests for GUI migration
- Add missing filters / auth in backend that exist in GUI
- Align and fix auth definition for assets
- Differentiate auth check on action and resource
- Refactoring when possible