Add missing auth flag in connector
Add canReadTransaction in connector
Auth flag that relies on user now check user tags
Normalized auth filter authorization
MODIFY
src/authorization/dynamic-data-source/OwnUserDynamicAuthorizationDataSource.ts
src/authorization/dynamic-data-source/OwnUserDynamicAuthorizationDataSource.ts
import { DynamicAuthorizationDataSourceName, OwnUserDynamicAuthorizationDataSourceData } from '../../types/Authorization';
+import Constants from '../../utils/Constants';
import DynamicAuthorizationDataSource from '../DynamicAuthorizationDataSource';
+import TagStorage from '../../storage/mongodb/TagStorage';
export default class OwnUserDynamicAuthorizationDataSource
extends DynamicAuthorizationDataSource<OwnUserDynamicAuthorizationDataSourceData> {
@@ -11,10 +13,23 @@ export default class OwnUserDynamicAuthorizationDataSource
public async loadData(): Promise<void> {
const ownUserData: OwnUserDynamicAuthorizationDataSourceData = {};
- // Get User ID
- ownUserData.userID = this.userToken.id;
+ // Get tags and user ID(s)
+ const data = await this.getUserTagIDs();
+ ownUserData.userID = data.userID;
+ ownUserData.tagIDs = data.tagIDs;
// Set
this.setData(ownUserData);
return Promise.resolve();
}
+
+ private async getUserTagIDs(): Promise<{ tagIDs: string[], userID: string }> {
+ // Get the tag and user Ids
+ const tags = await TagStorage.getTags(this.tenant,
+ {
+ userIDs: [this.userToken.id]
+ },
+ Constants.DB_PARAMS_DEFAULT_RECORD,
+ ['id']);
+ return { tagIDs: tags.result.map((tag) => tag.id), userID: this.userToken.id };
+ }
}

MODIFY
src/authorization/dynamic-data-source/SitesAdminUsersDynamicAuthorizationDataSource.ts
src/authorization/dynamic-data-source/SitesAdminUsersDynamicAuthorizationDataSource.ts
@@ -2,6 +2,7 @@ import { DynamicAuthorizationDataSourceName, SitesAdminUsersDynamicAuthorization
import Constants from '../../utils/Constants';
import DynamicAuthorizationDataSource from '../DynamicAuthorizationDataSource';
+import TagStorage from '../../storage/mongodb/TagStorage';
import UserStorage from '../../storage/mongodb/UserStorage';
export default class SitesAdminUsersDynamicAuthorizationDataSource
@@ -18,10 +19,11 @@ export default class SitesAdminUsersDynamicAuthorizationDataSource
// Set
sitesAdminData.siteIDs = data.siteIDs;
sitesAdminData.userID = data.userID;
+ sitesAdminData.tagIDs = data.tagIDs;
this.setData(sitesAdminData);
}
- private async getSitesAdminUserSiteIDs(): Promise<{siteIDs: string[], userID: string}> {
+ private async getSitesAdminUserSiteIDs(): Promise<{siteIDs: string[], tagIDs: string[], userID: string}> {
// Get the Site IDs of the Sites for which the user is Site Admin
const sites = await UserStorage.getUserSites(this.tenant,
{
@@ -30,6 +32,13 @@ export default class SitesAdminUsersDynamicAuthorizationDataSource
}, Constants.DB_PARAMS_MAX_LIMIT,
['siteID']
);
- return { siteIDs: sites.result.map((userSite) => userSite.siteID), userID: this.userToken.id };
+ // Get the tag and user Ids
+ const tags = await TagStorage.getTags(this.tenant,
+ {
+ userIDs: [this.userToken.id]
+ },
+ Constants.DB_PARAMS_DEFAULT_RECORD,
+ ['id']);
+ return { siteIDs: sites.result.map((userSite) => userSite.siteID),tagIDs: tags.result.map((tag) => tag.id), userID: this.userToken.id };
}
}

MODIFY
src/authorization/dynamic-filters/OwnUserDynamicAuthorizationFilter.ts
src/authorization/dynamic-filters/OwnUserDynamicAuthorizationFilter.ts
@@ -10,22 +10,49 @@ export default class OwnUserDynamicAuthorizationFilter extends DynamicAuthorizat
// Get User ID
const ownUserDataSource = this.getDataSource(
DynamicAuthorizationDataSourceName.OWN_USER) as OwnUserDynamicAuthorizationDataSource;
- const { userID } = ownUserDataSource.getData();
+ const { userID, tagIDs } = ownUserDataSource.getData();
+ // Flag
+ let authFilterUsed = false;
// Clear
authorizationFilters.filters.userIDs = [];
+ authorizationFilters.filters.ownUserTags = [];
if (userID) {
// Force the filter
authorizationFilters.filters.userIDs = [userID];
// Check if filter is provided
- if (Utils.objectHasProperty(extraFilters, 'UserID') &&
- !Utils.isNullOrUndefined(extraFilters['UserID'])) {
+ if (Utils.objectHasProperty(extraFilters, 'UserID') && !Utils.isNullOrUndefined(extraFilters['UserID'])) {
+ // Update flag
+ authFilterUsed = true;
const filteredUserIDs: string[] = extraFilters['UserID'].split('|');
// Override
authorizationFilters.filters.userIDs = filteredUserIDs.filter(
(user) => authorizationFilters.filters.userIDs.includes(user));
+ // Check auth
+ if (!Utils.isEmptyArray(authorizationFilters.filters.userIDs)) {
+ authorizationFilters.authorized = true;
}
}
- if (!Utils.isEmptyArray(authorizationFilters.filters.userIDs)) {
+ }
+ // Check tags only when extra filter is provided otherwise skip
+ if (!Utils.isEmptyArray(tagIDs)) {
+ // Force the filter
+ authorizationFilters.filters.ownUserTags = tagIDs;
+ // Check if filter is provided
+ if (Utils.objectHasProperty(extraFilters, 'TagIDs') && !Utils.isNullOrUndefined(extraFilters['TagIDs'])) {
+ // Update flag
+ authFilterUsed = true;
+ const filteredUserTagIDs: string[] = extraFilters['TagIDs'].split('|');
+ // Override
+ authorizationFilters.filters.ownUserTags = filteredUserTagIDs.filter(
+ (tag) => authorizationFilters.filters.ownUserTags.includes(tag));
+ // Check auth
+ if (!Utils.isEmptyArray(authorizationFilters.filters.ownUserTags)) {
+ authorizationFilters.authorized = true;
+ }
+ }
+ }
+ // No auth filter, we authorize
+ if (!authFilterUsed) {
authorizationFilters.authorized = true;
}
// Remove sensible data if not authorized and filter is provided

MODIFY
src/authorization/dynamic-filters/SitesAdminUsersDynamicAuthorizationFilter.ts
src/authorization/dynamic-filters/SitesAdminUsersDynamicAuthorizationFilter.ts
@@ -11,7 +11,9 @@ export default class SitesAdminUsersDynamicAuthorizationFilter extends DynamicAu
// Retrieve site ids where user is site admin and logged user id
const sitesAdminUsersDataSource = this.getDataSource(
DynamicAuthorizationDataSourceName.SITES_ADMIN_USERS) as SitesAdminUsersDynamicAuthorizationDataSource;
- const { siteIDs, userID } = sitesAdminUsersDataSource.getData();
+ const { siteIDs, tagIDs, userID } = sitesAdminUsersDataSource.getData();
+ // Flag
+ let authFilterUsed = false;
// Perform site ids check only if organization component is active
if (Utils.isTenantComponentActive(this.tenant, TenantComponents.ORGANIZATION)) {
// Init user site IDs
@@ -19,32 +21,58 @@ export default class SitesAdminUsersDynamicAuthorizationFilter extends DynamicAu
if (!Utils.isEmptyArray(siteIDs)) {
authorizationFilters.filters.siteAdminIDs = siteIDs;
// Check if filter is provided
- if (Utils.objectHasProperty(extraFilters, 'SiteID') &&
- !Utils.isNullOrUndefined(extraFilters['SiteID'])) {
+ if (Utils.objectHasProperty(extraFilters, 'SiteID') && !Utils.isNullOrUndefined(extraFilters['SiteID'])) {
+ // Update flag
+ authFilterUsed = true;
const filteredSiteIDs: string[] = extraFilters['SiteID'].split('|');
// Override
authorizationFilters.filters.siteAdminIDs = filteredSiteIDs.filter(
(siteID) => authorizationFilters.filters.siteAdminIDs.includes(siteID));
- }
- }
+ // Check auth
if (!Utils.isEmptyArray(authorizationFilters.filters.siteAdminIDs)) {
authorizationFilters.authorized = true;
}
}
+ }
+ }
// Check user filter
authorizationFilters.filters.ownerID = [];
if (userID) {
authorizationFilters.filters.ownerID = [userID];
// Check if filter is provided
- if (Utils.objectHasProperty(extraFilters, 'UserID') &&
- !Utils.isNullOrUndefined(extraFilters['UserID'])) {
+ if (Utils.objectHasProperty(extraFilters, 'UserID') && !Utils.isNullOrUndefined(extraFilters['UserID'])) {
+ // Update flag
+ authFilterUsed = true;
const filteredUserIDs: string[] = extraFilters['UserID'].split('|');
// Override
authorizationFilters.filters.ownerID = filteredUserIDs.filter(
(user) => authorizationFilters.filters.ownerID.includes(user));
+ // Check auth
+ if (!Utils.isEmptyArray(authorizationFilters.filters.ownerID)) {
+ authorizationFilters.authorized = true;
}
}
- if (!Utils.isEmptyArray(authorizationFilters.filters.ownerID)) {
+ }
+ // Check tags only when extra filter is provided otherwise skip
+ if (!Utils.isEmptyArray(tagIDs)) {
+ // Force the filter
+ authorizationFilters.filters.ownUserTags = tagIDs;
+ // Check if filter is provided
+ if (Utils.objectHasProperty(extraFilters, 'TagIDs') && !Utils.isNullOrUndefined(extraFilters['TagIDs'])) {
+ // Update flag
+ authFilterUsed = true;
+ const filteredUserTagIDs: string[] = extraFilters['TagIDs'].split('|');
+ // Override
+ authorizationFilters.filters.ownUserTags = filteredUserTagIDs.filter(
+ (tag) => authorizationFilters.filters.ownUserTags.includes(tag));
+ // Check auth
+ if (!Utils.isEmptyArray(authorizationFilters.filters.ownUserTags)) {
+ authorizationFilters.authorized = true;
+ }
+ }
+ }
+ // No auth filter, we authorize
+ if (!authFilterUsed) {
authorizationFilters.authorized = true;
}
// Remove sensible data if not authorized and filter is provided

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
@@ -901,6 +901,10 @@ export default class AuthorizationService {
ChargePointStatus.AVAILABLE,
ChargePointStatus.UNAVAILABLE,
].includes(connector.status);
+ // Read associated transaction: note we force UserID & TagIDs filter
+ connector.canReadTransaction = await AuthorizationService.canPerformAuthorizationAction(
+ tenant, userToken, Entity.TRANSACTION, Action.READ, authorizationFilter,
+ { chargingStationID: chargingStation.id, UserID: connector.user?.id || '', TagIDs: connector.currentTagID || '', SiteID: chargingStation.siteID });
// Remove sensible data
await AuthorizationService.canPerformAuthorizationAction(
tenant, userToken, Entity.CONNECTOR, Action.VIEW_USER_DATA, authorizationFilter,

MODIFY
src/types/Authorization.ts
src/types/Authorization.ts
@@ -332,6 +332,7 @@ export interface ConnectorAuthorizationActions extends AuthorizationActions {
canRemoteStopTransaction?:boolean;
canRemoteStartTransaction?:boolean;
canUnlockConnector?:boolean;
+ canReadTransaction?:boolean;
}
export interface ChargingProfileAuthorizationActions extends AuthorizationActions {
@@ -407,6 +408,7 @@ export interface SitesAdminOrOwnerDynamicAuthorizationDataSourceData extends Dyn
export interface SitesAdminUsersDynamicAuthorizationDataSourceData extends DynamicAuthorizationDataSourceData {
siteIDs?: string[];
userID?: string;
+ tagIDs?: string[];
}
export interface SitesOwnerDynamicAuthorizationDataSourceData extends DynamicAuthorizationDataSourceData {
siteIDs?: string[];
@@ -417,8 +419,10 @@ export interface AssignedSitesDynamicAuthorizationDataSourceData extends Dynamic
}
export interface SiteAdminUsersDynamicAuthorizationDataSourceData extends DynamicAuthorizationDataSourceData {
userIDs?: string[];
+ tagIDs?: string[]; // used ?
}
export interface OwnUserDynamicAuthorizationDataSourceData extends DynamicAuthorizationDataSourceData {
userID?: string;
+ tagIDs?: string[];
}

Add missing auth flag in connector

- Add canReadTransaction in connector
- Auth flag that relies on user now check user tags
- Normalized auth filter authorization