Refactor handleGetTag; add userIDs as filter in TagStorage method.
MODIFY
src/authorization/AuthorizationsDefinition.ts
src/authorization/AuthorizationsDefinition.ts
@@ -68,7 +68,12 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
]
},
{ resource: Entity.TAGS, action: [Action.IMPORT, Action.EXPORT], attributes: ['*'] },
- { resource: Entity.TAG, action: [Action.CREATE, Action.UPDATE, Action.DELETE, Action.READ], attributes: ['*'] },
+ {
+ resource: Entity.TAG, action: Action.READ, attributes: [
+ 'id', 'userID', 'issuer', 'active', 'description', 'default', 'user.id', 'user.name', 'user.firstName', 'user.email'
+ ]
+ },
+ { resource: Entity.TAG, action: [Action.CREATE, Action.UPDATE, Action.DELETE], attributes: ['*'] },
{ resource: Entity.CHARGING_PROFILES, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.CHARGING_PROFILE, action: [Action.READ], attributes: ['*'] },
{ resource: Entity.COMPANY, action: Action.READ, attributes: ['id', 'name', 'issuer', 'logo', 'address'] },
@@ -330,10 +335,18 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
],
condition: {
Fn: 'custom:dynamicAuthorizationFilters',
- args: { filters: ['OwnUser'] }
+ args: { filters: ['OwnUser', 'SiteAdminUsers'] }
+ }
+ },
+ {
+ resource: Entity.TAG, action: Action.READ, attributes: [
+ 'id', 'userID', 'issuer', 'active', 'description', 'default', 'user.id', 'user.name', 'user.firstName', 'user.email'
+ ],
+ condition: {
+ Fn: 'custom:dynamicAuthorizationFilters',
+ args: { filters: ['OwnUser', 'SiteAdminUsers'] }
}
},
- { resource: Entity.TAG, action: Action.READ, attributes: ['*'] },
{
resource: Entity.CHARGING_STATION,
action: [Action.REMOTE_STOP_TRANSACTION, Action.STOP_TRANSACTION],
@@ -554,16 +567,25 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
attributes: ['*'],
args: { 'sites': '$.site' }
},
- {
- resource: Entity.TAGS, action: Action.LIST, attributes: [
- 'id', 'userID', 'active', 'ocpiToken', 'description', 'issuer', 'default',
- 'createdOn', 'lastChangedOn'
- ],
- condition: {
- Fn: 'custom:dynamicAuthorizationFilters',
- args: { filters: ['SiteAdminUsers'] }
- }
- },
+ // {
+ // resource: Entity.TAG, action: Action.READ, attributes: [
+ // 'id', 'userID', 'issuer', 'active', 'description', 'default', 'user.id', 'user.name', 'user.firstName', 'user.email'
+ // ],
+ // condition: {
+ // Fn: 'custom:dynamicAuthorizationFilters',
+ // args: { filters: ['SiteAdminUsers'] }
+ // }
+ // },
+ // {
+ // resource: Entity.TAGS, action: Action.LIST, attributes: [
+ // 'id', 'userID', 'active', 'ocpiToken', 'description', 'issuer', 'default',
+ // 'createdOn', 'lastChangedOn'
+ // ],
+ // condition: {
+ // Fn: 'custom:dynamicAuthorizationFilters',
+ // args: { filters: ['SiteAdminUsers'] }
+ // }
+ // },
{ resource: Entity.TAGS, action: Action.EXPORT, attributes: ['*'] },
]
},

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
@@ -410,19 +410,15 @@ export default class AuthorizationService {
}
public static async checkAndGetTagAuthorizationFilters(tenant: Tenant, userToken: UserToken,
- filteredRequest: HttpByIDRequest): Promise<AuthorizationFilter> {
+ filteredRequest: HttpByIDRequest, action: Action): Promise<AuthorizationFilter> {
const authorizationFilters: AuthorizationFilter = {
filters: {},
dataSources: new Map(),
- projectFields: ['id', 'userID', 'issuer', 'active', 'description', 'default', 'user.id', 'user.name', 'user.firstName', 'user.email'],
- authorized: userToken.role === UserRole.ADMIN || userToken.role === UserRole.SUPER_ADMIN,
+ projectFields: [],
+ authorized: false
};
- // Filter projected fields
- authorizationFilters.projectFields = AuthorizationService.filterProjectFields(
- authorizationFilters.projectFields, filteredRequest.ProjectFields);
- // Handle Sites
- await AuthorizationService.checkAssignedSiteAdminsAndOwners(
- tenant, userToken, null, authorizationFilters);
+ // Check static & dynamic authorization
+ await this.canPerformAuthorizationAction(tenant, userToken, Entity.TAG, action, authorizationFilters, filteredRequest);
return authorizationFilters;
}

MODIFY
src/server/rest/v1/service/TagService.ts
src/server/rest/v1/service/TagService.ts
@@ -42,31 +42,11 @@ const MODULE_NAME = 'TagService';
export default class TagService {
public static async handleGetTag(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ // Filter request
const filteredRequest = TagSecurity.filterTagRequestByID(req.query);
- // Check auth
- if (!await Authorizations.canReadTag(req.user)) {
- throw new AppAuthError({
- errorCode: HTTPAuthError.FORBIDDEN,
- user: req.user,
- action: Action.READ, entity: Entity.TAG,
- module: MODULE_NAME, method: 'handleGetTag'
- });
- }
- UtilsService.assertIdIsProvided(action, filteredRequest.ID, MODULE_NAME, 'handleGetTag', req.user);
- // Get authorization filters
- const authorizationTagFilters = await AuthorizationService.checkAndGetTagAuthorizationFilters(
- req.tenant, req.user, filteredRequest);
- // Get the tag
- const tag = await TagStorage.getTag(req.user.tenantID, filteredRequest.ID, { withUser: true },
- authorizationTagFilters.projectFields
- );
- UtilsService.assertObjectExists(action, tag, `Tag ID '${filteredRequest.ID}' does not exist`,
- MODULE_NAME, 'handleGetTag', req.user);
- // Check Users
- if (!await Authorizations.canReadUser(req.user)) {
- delete tag.userID;
- delete tag.user;
- }
+ // Check and Get Tag
+ const tag = await UtilsService.checkAndGetTagAuthorization(req.tenant, req.user, filteredRequest.ID, Action.READ, action,
+ { withUser: true }, true);
// Return
res.json(tag);
next();

MODIFY
src/server/rest/v1/service/UtilsService.ts
src/server/rest/v1/service/UtilsService.ts
@@ -11,7 +11,6 @@ import Asset from '../../../../types/Asset';
import AssetStorage from '../../../../storage/mongodb/AssetStorage';
import AuthorizationService from './AuthorizationService';
import Authorizations from '../../../../authorization/Authorizations';
-import BackendError from '../../../../exception/BackendError';
import { ChargingProfile } from '../../../../types/ChargingProfile';
import ChargingStationStorage from '../../../../storage/mongodb/ChargingStationStorage';
import Company from '../../../../types/Company';
@@ -25,12 +24,12 @@ import OCPIEndpoint from '../../../../types/ocpi/OCPIEndpoint';
import OICPEndpoint from '../../../../types/oicp/OICPEndpoint';
import PDFDocument from 'pdfkit';
import { ServerAction } from '../../../../types/Server';
-import { Setting } from '../../../../types/Setting';
import Site from '../../../../types/Site';
import SiteArea from '../../../../types/SiteArea';
import SiteAreaStorage from '../../../../storage/mongodb/SiteAreaStorage';
import SiteStorage from '../../../../storage/mongodb/SiteStorage';
import Tag from '../../../../types/Tag';
+import TagStorage from '../../../../storage/mongodb/TagStorage';
import Tenant from '../../../../types/Tenant';
import TenantComponents from '../../../../types/TenantComponents';
import { TransactionInErrorType } from '../../../../types/InError';
@@ -475,7 +474,7 @@ export default class UtilsService {
value: siteAreaID
});
}
- // Get SiteArea
+ // Get SiteArea & check it exists
const siteArea = await SiteAreaStorage.getSiteArea(tenant.id, siteAreaID,
{
...additionalFilters,
@@ -512,6 +511,43 @@ export default class UtilsService {
return siteArea;
}
+ public static async checkAndGetTagAuthorization(tenant: Tenant, userToken:UserToken, tagID: string, authAction: Action,
+ action: ServerAction, additionalFilters: Record<string, any>, applyProjectFields = false): Promise<Tag> {
+ // Check mandatory fields
+ UtilsService.assertIdIsProvided(action, tagID, MODULE_NAME, 'checkAndGetTagAuthorization', userToken);
+ // Get dynamic auth
+ const authorizationFilter = await AuthorizationService.checkAndGetTagAuthorizationFilters(tenant, userToken,
+ { ID: tagID }, Action.READ);
+ if (!authorizationFilter.authorized) {
+ throw new AppAuthError({
+ errorCode: HTTPAuthError.FORBIDDEN,
+ user: userToken,
+ action: Action.READ, entity: Entity.TAG,
+ module: MODULE_NAME, method: 'checkAndGetTagAuthorization',
+ value: tagID
+ });
+ }
+ // Get the Tag & check it exists
+ const tag = await TagStorage.getTag(userToken.tenantID, tagID,
+ {
+ ...additionalFilters,
+ ...authorizationFilter.filters
+ },
+ applyProjectFields ? authorizationFilter.projectFields : null
+ );
+ UtilsService.assertObjectExists(action, tag, `Tag ID '${tagID}' does not exist`,
+ MODULE_NAME, 'handleGetTag', userToken);
+ // Check Users
+ // Get authorization filters for users
+ const authorizationUsersFilters = await AuthorizationService.checkAndGetUsersAuthorizationFilters(
+ tenant, userToken);
+ if (!authorizationUsersFilters.authorized) {
+ delete tag.userID;
+ delete tag.user;
+ }
+ return tag;
+ }
+
public static sendEmptyDataResult(res: Response, next: NextFunction): void {
res.json(Constants.DB_EMPTY_DATA_RESULT);
next();

MODIFY
src/storage/mongodb/TagStorage.ts
src/storage/mongodb/TagStorage.ts
@@ -251,11 +251,12 @@ export default class TagStorage {
}
public static async getTag(tenantID: string, id: string,
- params: { withUser?: boolean; withNbrTransactions?: boolean } = {}, projectFields?: string[]): Promise<Tag> {
+ params: { withUser?: boolean; withNbrTransactions?: boolean, userIDs?: string[] } = {}, projectFields?: string[]): Promise<Tag> {
const tagMDB = await TagStorage.getTags(tenantID, {
tagIDs: [id],
withUser: params.withUser,
withNbrTransactions: params.withNbrTransactions,
+ userIDs: params.userIDs
}, Constants.DB_PARAMS_SINGLE_RECORD, projectFields);
return tagMDB.count === 1 ? tagMDB.result[0] : null;
}

Refactor handleGetTag; add userIDs as filter in TagStorage method.