Migrate setting service to abac
MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
import { Action, AuthorizationActions, AuthorizationContext, AuthorizationFilter, DynamicAuthorizationsFilter, Entity } from '../../../../types/Authorization';
-import { AssetDataResult, BillingAccountsDataResult, BillingInvoiceDataResult, BillingPaymentMethodDataResult, BillingTaxDataResult, BillingTransfersDataResult, CarCatalogDataResult, CarDataResult, ChargingProfileDataResult, ChargingStationDataResult, ChargingStationTemplateDataResult, CompanyDataResult, DataResult, LogDataResult, PricingDefinitionDataResult, RegistrationTokenDataResult, SiteAreaDataResult, SiteDataResult, SiteUserDataResult, TagDataResult, TransactionDataResult, TransactionInErrorDataResult, UserDataResult, UserSiteDataResult } from '../../../../types/DataResult';
+import { AssetDataResult, BillingAccountsDataResult, BillingInvoiceDataResult, BillingPaymentMethodDataResult, BillingTaxDataResult, BillingTransfersDataResult, CarCatalogDataResult, CarDataResult, ChargingProfileDataResult, ChargingStationDataResult, ChargingStationTemplateDataResult, CompanyDataResult, LogDataResult, PricingDefinitionDataResult, RegistrationTokenDataResult, SettingDBDataResult, SiteAreaDataResult, SiteDataResult, SiteUserDataResult, TagDataResult, TransactionDataResult, TransactionInErrorDataResult, UserDataResult, UserSiteDataResult } from '../../../../types/DataResult';
import { BillingAccount, BillingInvoice, BillingPaymentMethod, BillingTax, BillingTransfer } from '../../../../types/Billing';
import { Car, CarCatalog } from '../../../../types/Car';
import { ChargePointStatus, OCPPProtocol, OCPPVersion } from '../../../../types/ocpp/OCPPServer';
@@ -11,14 +11,13 @@ import { HttpChargingProfileRequest, HttpChargingProfilesGetRequest, HttpChargin
import { HttpChargingStationTemplateGetRequest, HttpChargingStationTemplatesGetRequest } from '../../../../types/requests/HttpChargingStationTemplateRequest';
import { HttpCompaniesGetRequest, HttpCompanyGetRequest } from '../../../../types/requests/HttpCompanyRequest';
import { HttpPricingDefinitionGetRequest, HttpPricingDefinitionsGetRequest } from '../../../../types/requests/HttpPricingRequest';
+import { HttpSettingGetRequest, HttpSettingsGetRequest } from '../../../../types/requests/HttpSettingRequest';
import { HttpSiteAreaGetRequest, HttpSiteAreasGetRequest } from '../../../../types/requests/HttpSiteAreaRequest';
import { HttpSiteAssignUsersRequest, HttpSiteGetRequest, HttpSiteUsersRequest } from '../../../../types/requests/HttpSiteRequest';
import { HttpTagGetRequest, HttpTagsGetRequest } from '../../../../types/requests/HttpTagRequest';
import { HttpTransactionConsumptionsGetRequest, HttpTransactionGetRequest } from '../../../../types/requests/HttpTransactionRequest';
import { HttpUserGetRequest, HttpUserSitesAssignRequest, HttpUserSitesGetRequest, HttpUsersGetRequest } from '../../../../types/requests/HttpUserRequest';
import RefundReport, { RefundStatus } from '../../../../types/Refund';
-import Tenant, { TenantComponents } from '../../../../types/Tenant';
-import User, { UserRole } from '../../../../types/User';
import AppAuthError from '../../../../exception/AppAuthError';
import Asset from '../../../../types/Asset';
@@ -31,7 +30,6 @@ import { HTTPAuthError } from '../../../../types/HTTPError';
import HttpByIDRequest from '../../../../types/requests/HttpByIDRequest';
import { HttpLogGetRequest } from '../../../../types/requests/HttpLogRequest';
import { HttpRegistrationTokenGetRequest } from '../../../../types/requests/HttpRegistrationToken';
-import { HttpSettingGetRequest } from '../../../../types/requests/HttpSettingRequest';
import { Log } from '../../../../types/Log';
import { OCPICapability } from '../../../../types/ocpi/OCPIEvse';
import PricingDefinition from '../../../../types/Pricing';
@@ -41,8 +39,10 @@ import { Setting } from '../../../../types/Setting';
import Site from '../../../../types/Site';
import SiteArea from '../../../../types/SiteArea';
import Tag from '../../../../types/Tag';
+import Tenant from '../../../../types/Tenant';
import Transaction from '../../../../types/Transaction';
import { TransactionInError } from '../../../../types/InError';
+import User from '../../../../types/User';
import UserToken from '../../../../types/UserToken';
import Utils from '../../../../utils/Utils';
import _ from 'lodash';
@@ -1114,7 +1114,8 @@ export default class AuthorizationService {
Utils.removeCanPropertiesWithFalseValue(billingPaymentMethod);
}
- public static async checkAndGetSettingsAuthorizations(tenant: Tenant, userToken: UserToken): Promise<AuthorizationFilter> {
+ public static async checkAndGetSettingsAuthorizations(tenant: Tenant, userToken: UserToken,
+ authAction: Action, filteredRequest: Partial<HttpPaymentMethods>, failsWithException = true): Promise<AuthorizationFilter> {
const authorizations: AuthorizationFilter = {
filters: {},
dataSources: new Map(),
@@ -1123,7 +1124,7 @@ export default class AuthorizationService {
};
// Check static & dynamic authorization
await AuthorizationService.canPerformAuthorizationAction(
- tenant, userToken, Entity.SETTING, Action.LIST, authorizations, null, null, true);
+ tenant, userToken, Entity.SETTING, Action.LIST, authorizations, filteredRequest, null, failsWithException);
return authorizations;
}
@@ -1133,10 +1134,13 @@ export default class AuthorizationService {
tenant, Entity.SETTING, userToken, filteredRequest, filteredRequest.ID ? { SettingID: filteredRequest.ID } : {}, authAction, entityData);
}
- public static async addSettingsAuthorizations(tenant: Tenant, userToken: UserToken, settings: DataResult<Setting>,
- authorizationFilter: AuthorizationFilter): Promise<void> {
+ public static async addSettingsAuthorizations(tenant: Tenant, userToken: UserToken, settings: SettingDBDataResult, authorizationFilter: AuthorizationFilter,
+ filteredRequest: Partial<HttpSettingsGetRequest>): Promise<void> {
// Add Meta Data
settings.metadata = authorizationFilter.metadata;
+ // Add Authorizations
+ settings.canCreate = await AuthorizationService.canPerformAuthorizationAction(
+ tenant, userToken, Entity.SETTING, Action.CREATE, authorizationFilter, filteredRequest.Identifier ? { ID: filteredRequest.Identifier } : {});
for (const setting of settings.result) {
await AuthorizationService.addSettingAuthorizations(tenant, userToken, setting, authorizationFilter);
}
@@ -1144,8 +1148,8 @@ export default class AuthorizationService {
public static async addSettingAuthorizations(tenant: Tenant, userToken: UserToken, setting: Setting, authorizationFilter: AuthorizationFilter): Promise<void> {
setting.canRead = true; // Always true as it should be filtered upfront
- setting.canUpdate = await AuthorizationService.canPerformAuthorizationAction(
- tenant, userToken, Entity.SETTING, Action.UPDATE, authorizationFilter);
+ setting.canUpdate = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.SETTING, Action.UPDATE, authorizationFilter);
+ setting.canDelete = await AuthorizationService.canPerformAuthorizationAction(tenant, userToken, Entity.SETTING, Action.DELETE, authorizationFilter);
// Remove auth flags set to false
Utils.removeCanPropertiesWithFalseValue(setting);
}

MODIFY
src/server/rest/v1/service/SettingService.ts
src/server/rest/v1/service/SettingService.ts
-import { Action, Entity } from '../../../../types/Authorization';
-import { HTTPAuthError, HTTPError } from '../../../../types/HTTPError';
import { IntegrationSettings, PricingSettingsType, SettingDB, TechnicalSettings } from '../../../../types/Setting';
import { NextFunction, Request, Response } from 'express';
-import AppAuthError from '../../../../exception/AppAuthError';
+import { Action } from '../../../../types/Authorization';
import AppError from '../../../../exception/AppError';
-import Authorizations from '../../../../authorization/Authorizations';
+import AuthorizationService from './AuthorizationService';
import Constants from '../../../../utils/Constants';
import Cypher from '../../../../utils/Cypher';
+import { HTTPError } from '../../../../types/HTTPError';
import Logging from '../../../../utils/Logging';
import { ServerAction } from '../../../../types/Server';
import SettingStorage from '../../../../storage/mongodb/SettingStorage';
@@ -46,12 +45,7 @@ export default class SettingService {
// Get it
const setting = await UtilsService.checkAndGetSettingAuthorization(req.tenant, req.user, settingID, Action.READ, action, {}, {}, true);
// Process the sensitive data if any
- // Hash sensitive data before being sent to the front end
- Cypher.hashSensitiveDataInJSON(setting);
- // If Crypto Settings, hash key
- if (setting.identifier === 'crypto') {
- setting.content.crypto.key = Utils.hash(setting.content.crypto.key);
- }
+ SettingService.hashSensitiveData(setting);
res.json(setting);
next();
}
@@ -62,57 +56,52 @@ export default class SettingService {
// Get it
const setting = await UtilsService.checkAndGetSettingAuthorization(req.tenant, req.user, settingID, Action.READ, action, {}, {}, true);
// Process the sensitive data if any
- // Hash sensitive data before being sent to the front end
- Cypher.hashSensitiveDataInJSON(setting);
- // If Crypto Settings, hash key
- if (setting.identifier === 'crypto') {
- setting.content.crypto.key = Utils.hash(setting.content.crypto.key);
- }
+ SettingService.hashSensitiveData(setting);
res.json(setting);
next();
}
public static async handleGetSettings(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
- // Check auth
- if (!await Authorizations.canListSettings(req.user)) {
- throw new AppAuthError({
- errorCode: HTTPAuthError.FORBIDDEN,
- user: req.user,
- action: Action.LIST, entity: Entity.SETTING,
- module: MODULE_NAME, method: 'handleGetSettings'
- });
- }
// Filter
const filteredRequest = SettingValidatorRest.getInstance().validateSettingsGetReq(req.query);
- // Get the all settings identifier
+ // Get authorization filters
+ const authorizations = await AuthorizationService.checkAndGetSettingsAuthorizations(req.tenant, req.user, Action.LIST, filteredRequest, false);
+ if (!authorizations.authorized) {
+ UtilsService.sendEmptyDataResult(res, next);
+ }
+ // Get the settings
const settings = await SettingStorage.getSettings(req.tenant,
- { identifier: filteredRequest.Identifier },
- { limit: filteredRequest.Limit, skip: filteredRequest.Skip, sort: filteredRequest.SortFields });
+ {
+ identifier: filteredRequest.Identifier,
+ ...authorizations.filters
+ },
+ {
+ limit: filteredRequest.Limit,
+ skip: filteredRequest.Skip,
+ sort: filteredRequest.SortFields
+ },
+ authorizations.projectFields
+ );
+ // Assign projected fields
+ if (authorizations.projectFields) {
+ settings.projectFields = authorizations.projectFields;
+ }
+ // Add Auth flags
+ await AuthorizationService.addSettingsAuthorizations(req.tenant, req.user, settings, authorizations, filteredRequest);
// Process the sensitive data if any
for (const setting of settings.result) {
- // Hash sensitive data before being sent to the front end
- Cypher.hashSensitiveDataInJSON(setting);
- // If Crypto Settings, hash key
- if (setting.identifier === 'crypto') {
- setting.content.crypto.key = Utils.hash(setting.content.crypto.key);
- }
+ // Process the sensitive data if any
+ SettingService.hashSensitiveData(setting);
}
res.json(settings);
next();
}
public static async handleCreateSetting(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
- // Check auth
- if (!await Authorizations.canCreateSetting(req.user)) {
- throw new AppAuthError({
- errorCode: HTTPAuthError.FORBIDDEN,
- user: req.user,
- action: Action.CREATE, entity: Entity.SETTING,
- module: MODULE_NAME, method: 'handleCreateSetting'
- });
- }
// Filter
const filteredRequest = SettingService.filterSetting(action, req);
+ // Check auth
+ await AuthorizationService.checkAndGetSettingAuthorizations(req.tenant,req.user, {}, Action.CREATE, filteredRequest);
// Process the sensitive data if any
await Cypher.encryptSensitiveDataInJSON(req.tenant, filteredRequest);
// Update timestamp
@@ -133,6 +122,7 @@ export default class SettingService {
}
public static async handleUpdateSetting(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ // Filter
const filteredRequest = SettingService.filterSetting(action, req);
// Get Setting
const setting = await UtilsService.checkAndGetSettingAuthorization(req.tenant, req.user, filteredRequest.id, Action.UPDATE, action, {}, {}, true);
@@ -300,4 +290,13 @@ export default class SettingService {
});
}
}
+
+ private static hashSensitiveData(setting: SettingDB): void {
+ // Hash sensitive data before being sent to the front end
+ Cypher.hashSensitiveDataInJSON(setting);
+ // If Crypto Settings, hash key
+ if (setting.identifier === 'crypto') {
+ setting.content.crypto.key = Utils.hash(setting.content.crypto.key);
+ }
+ }
}

MODIFY
src/storage/mongodb/SettingStorage.ts
src/storage/mongodb/SettingStorage.ts
-import { AnalyticsSettings, AnalyticsSettingsType, AssetSettings, AssetSettingsType, BillingSetting, BillingSettings, BillingSettingsType, CarConnectorSetting, CarConnectorSettings, CarConnectorSettingsType, CryptoSetting, CryptoSettings, CryptoSettingsType, PricingSettings, PricingSettingsType, RefundSettings, RefundSettingsType, RoamingSettings, SettingDB, SmartChargingSettings, SmartChargingSettingsType, TechnicalSettings, UserSettings, UserSettingsType } from '../../types/Setting';
+import { AnalyticsSettings, AnalyticsSettingsType, AssetSettings, AssetSettingsType, BillingSetting, BillingSettings, BillingSettingsType, CarConnectorSettings, CarConnectorSettingsType, CryptoSetting, CryptoSettings, CryptoSettingsType, PricingSettings, PricingSettingsType, RefundSettings, RefundSettingsType, RoamingSettings, SettingDB, SmartChargingSettings, SmartChargingSettingsType, TechnicalSettings, UserSettings, UserSettingsType } from '../../types/Setting';
import Tenant, { TenantComponents } from '../../types/Tenant';
import global, { DatabaseCount, FilterParams } from '../../types/GlobalType';
import BackendError from '../../exception/BackendError';
import Constants from '../../utils/Constants';
-import { DataResult } from '../../types/DataResult';
import DatabaseUtils from './DatabaseUtils';
import DbParams from '../../types/database/DbParams';
import Logging from '../../utils/Logging';
import { ObjectId } from 'mongodb';
+import { SettingDBDataResult } from '../../types/DataResult';
import Utils from '../../utils/Utils';
const MODULE_NAME = 'SettingStorage';
@@ -334,7 +334,7 @@ export default class SettingStorage {
public static async getSettings(tenant: Tenant,
params: {identifier?: string; settingID?: string, dateFrom?: Date, dateTo?: Date},
- dbParams: DbParams, projectFields?: string[]): Promise<DataResult<SettingDB>> {
+ dbParams: DbParams, projectFields?: string[]): Promise<SettingDBDataResult> {
const startTime = Logging.traceDatabaseRequestStart();
DatabaseUtils.checkTenantObject(tenant);
// Clone before updating the values

MODIFY
src/types/DataResult.ts
src/types/DataResult.ts
@@ -13,6 +13,7 @@ import Company from './Company';
import { Log } from './Log';
import PricingDefinition from './Pricing';
import RegistrationToken from './RegistrationToken';
+import { SettingDB } from './Setting';
import SiteArea from './SiteArea';
import Tag from './Tag';
@@ -177,3 +178,7 @@ export interface ChargingStationInErrorDataResult extends DataResult<ChargingSta
export interface ChargingProfileDataResult extends DataResult<ChargingProfile> {
canListChargingStations?:boolean;
}
+
+export interface SettingDBDataResult extends DataResult<SettingDB> {
+ canCreate?: boolean;
+}

Migrate setting service to abac