New auth concept for handleGetCars
MODIFY
src/authorization/AuthorizationsDefinition.ts
src/authorization/AuthorizationsDefinition.ts
@@ -128,7 +128,13 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
{ resource: Entity.CAR_CATALOGS, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.CAR_CATALOG, action: Action.READ, attributes: ['*'] },
{ resource: Entity.CAR, action: [Action.CREATE, Action.READ, Action.UPDATE, Action.DELETE], attributes: ['*'] },
- { resource: Entity.CARS, action: Action.LIST, attributes: ['*'] },
+ {
+ resource: Entity.CARS, action: Action.LIST, attributes: [
+ 'id', 'type', 'vin', 'licensePlate', 'converter', 'default', 'owner', 'createdOn', 'lastChangedOn',
+ 'carCatalog.id', 'carCatalog.vehicleMake', 'carCatalog.vehicleModel', 'carCatalog.vehicleModelVersion',
+ 'carCatalog.image', 'carCatalog.fastChargePowerMax', 'carCatalog.batteryCapacityFull'
+ ]
+ },
{ resource: Entity.USERS_CARS, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.USERS_CARS, action: Action.ASSIGN, attributes: ['*'] },
{ resource: Entity.NOTIFICATION, action: Action.CREATE, attributes: ['*'] },
@@ -165,7 +171,13 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
{ resource: Entity.CAR_CATALOGS, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.CAR_CATALOG, action: Action.READ, attributes: ['*'] },
{ resource: Entity.CAR, action: [Action.CREATE, Action.READ, Action.UPDATE, Action.DELETE], attributes: ['*'] },
- { resource: Entity.CARS, action: Action.LIST, attributes: ['*'] },
+ {
+ resource: Entity.CARS, action: Action.LIST, attributes: [
+ 'id', 'type', 'vin', 'licensePlate', 'converter', 'default', 'owner', 'createdOn', 'lastChangedOn',
+ 'carCatalog.id', 'carCatalog.vehicleMake', 'carCatalog.vehicleModel', 'carCatalog.vehicleModelVersion',
+ 'carCatalog.image', 'carCatalog.fastChargePowerMax', 'carCatalog.batteryCapacityFull'
+ ]
+ },
{
resource: Entity.COMPANIES, action: Action.LIST,
condition: {
@@ -307,7 +319,13 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
{ resource: Entity.CAR_CATALOGS, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.CAR_CATALOG, action: Action.READ, attributes: ['*'] },
{ resource: Entity.CAR, action: Action.READ, attributes: ['*'] },
- { resource: Entity.CARS, action: Action.LIST, attributes: ['*'] },
+ {
+ resource: Entity.CARS, action: Action.LIST, attributes: [
+ 'id', 'type', 'vin', 'licensePlate', 'converter', 'default', 'owner', 'createdOn', 'lastChangedOn',
+ 'carCatalog.id', 'carCatalog.vehicleMake', 'carCatalog.vehicleModel', 'carCatalog.vehicleModelVersion',
+ 'carCatalog.image', 'carCatalog.fastChargePowerMax', 'carCatalog.batteryCapacityFull'
+ ]
+ },
{
resource: Entity.COMPANIES, action: Action.LIST, attributes: [
'id', 'name', 'address', 'logo', 'issuer', 'distanceMeters', 'createdOn', 'lastChangedOn'

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
@@ -16,6 +16,7 @@ import DynamicAuthorizationFactory from '../../../../authorization/DynamicAuthor
import { HTTPAuthError } from '../../../../types/HTTPError';
import { HttpAssetsRequest } from '../../../../types/requests/HttpAssetRequest';
import HttpByIDRequest from '../../../../types/requests/HttpByIDRequest';
+import { HttpCarsRequest } from '../../../../types/requests/HttpCarRequest';
import { HttpChargingStationRequest } from '../../../../types/requests/HttpChargingStationRequest';
import { ServerAction } from '../../../../types/Server';
import Site from '../../../../types/Site';
@@ -668,6 +669,20 @@ export default class AuthorizationService {
return authorizationFilters;
}
+ public static async checkAndGetCarsAuthorizationFilters(tenant: Tenant, userToken: UserToken, filteredRequest: HttpCarsRequest) {
+ const authorizationFilters: AuthorizationFilter = {
+ filters: {},
+ dataSources: new Map(),
+ projectFields: [ ],
+ authorized: false
+ };
+
+ // Check static & dynamic authorization
+ await this.canPerformAuthorizationAction(
+ tenant, userToken, Entity.CARS, Action.LIST, authorizationFilters, filteredRequest);
+ return authorizationFilters;
+ }
+
public static async getSiteAdminSiteIDs(tenantID: string, userToken: UserToken): Promise<string[]> {
// Get the Sites where the user is Site Admin
const userSites = await UserStorage.getUserSites(tenantID,

MODIFY
src/server/rest/v1/service/CarService.ts
src/server/rest/v1/service/CarService.ts
@@ -7,6 +7,7 @@ import { NextFunction, Request, Response } from 'express';
import AppAuthError from '../../../../exception/AppAuthError';
import AppError from '../../../../exception/AppError';
import AsyncTaskManager from '../../../../async-task/AsyncTaskManager';
+import AuthorizationService from './AuthorizationService';
import Authorizations from '../../../../authorization/Authorizations';
import CarSecurity from './security/CarSecurity';
import CarStorage from '../../../../storage/mongodb/CarStorage';
@@ -216,6 +217,8 @@ export default class CarService {
next();
}
+ // todo: above this are the car catalogs
+
public static async handleCreateCar(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
let newCar: Car;
// Check if component is active
@@ -414,37 +417,40 @@ export default class CarService {
// Check if component is active
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.CAR, Action.LIST, Entity.CARS,
MODULE_NAME, 'handleGetCars');
+ // Filter
+ const filteredRequest = CarSecurity.filterCarsRequest(req.query);
// Check auth
- if (!await Authorizations.canListCars(req.user)) {
- throw new AppAuthError({
- errorCode: HTTPAuthError.FORBIDDEN,
- user: req.user,
- action: Action.LIST, entity: Entity.CARS,
- module: MODULE_NAME, method: 'handleGetCars'
- });
+ const authorizationCarsFilter = await AuthorizationService.checkAndGetCarsAuthorizationFilters(req.tenant, req.user, filteredRequest);
+ if (!authorizationCarsFilter.authorized) {
+ UtilsService.sendEmptyDataResult(res, next);
+ return;
}
- const filteredRequest = CarSecurity.filterCarsRequest(req.query);
// Check User
let userProject: string[] = [];
if (await Authorizations.canListUsers(req.user)) {
userProject = [ 'createdBy.name', 'createdBy.firstName', 'lastChangedBy.name', 'lastChangedBy.firstName',
'carUsers.user.id', 'carUsers.user.name', 'carUsers.user.firstName', 'carUsers.owner', 'carUsers.default' ];
+ // todo: is it ok like this?
+ authorizationCarsFilter.projectFields = authorizationCarsFilter.projectFields.concat(userProject);
}
// Get cars
const cars = await CarStorage.getCars(req.user.tenantID,
{
search: filteredRequest.Search,
+ // todo: should this be replaced by a dynamic filter?
userIDs: Authorizations.isBasic(req.user) ? [req.user.id] : filteredRequest.UserID ? filteredRequest.UserID.split('|') : null,
carMakers: filteredRequest.CarMaker ? filteredRequest.CarMaker.split('|') : null,
withUsers: filteredRequest.WithUsers
},
- { limit: filteredRequest.Limit, skip: filteredRequest.Skip, sort: filteredRequest.SortFields, onlyRecordCount: filteredRequest.OnlyRecordCount },
- [
- 'id', 'type', 'vin', 'licensePlate', 'converter', 'default', 'owner', 'createdOn', 'lastChangedOn',
- 'carCatalog.id', 'carCatalog.vehicleMake', 'carCatalog.vehicleModel', 'carCatalog.vehicleModelVersion',
- 'carCatalog.image', 'carCatalog.fastChargePowerMax', 'carCatalog.batteryCapacityFull',
- ...userProject
- ]);
+ {
+ limit: filteredRequest.Limit,
+ skip: filteredRequest.Skip,
+ sort: filteredRequest.SortFields,
+ onlyRecordCount: filteredRequest.OnlyRecordCount
+ },
+ authorizationCarsFilter.projectFields
+ );
+ // Return
res.json(cars);
next();
}

New auth concept for handleGetCars