Small clean and refactor of authorizations
Move issuer check in auth definition when possible
Update Auth definition with issuer constraint on actions
MODIFY
src/authorization/AuthorizationsDefinition.ts
src/authorization/AuthorizationsDefinition.ts
@@ -31,12 +31,26 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
Fn: 'custom:dynamicAuthorizations',
args: {
asserts: [],
- filters: ['-OwnUser']
+ filters: ['-OwnUser', 'LocalIssuer']
}
}
},
{
- resource: Entity.USER, action: [Action.READ, Action.CREATE, Action.UPDATE],
+ resource: Entity.USER, action: [Action.READ, Action.CREATE],
+ attributes: [
+ 'id', 'name', 'firstName', 'email', 'role', 'status', 'issuer', 'locale', 'plateID',
+ 'notificationsActive', 'notifications', 'phone', 'mobile', 'iNumber', 'costCenter', 'address'
+ ]
+ },
+ {
+ resource: Entity.USER, action: Action.UPDATE,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['LocalIssuer']
+ }
+ },
attributes: [
'id', 'name', 'firstName', 'email', 'role', 'status', 'issuer', 'locale', 'plateID',
'notificationsActive', 'notifications', 'phone', 'mobile', 'iNumber', 'costCenter', 'address'
@@ -123,12 +137,26 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
Fn: 'custom:dynamicAuthorizations',
args: {
asserts: [],
- filters: ['-OwnUser']
+ filters: ['-OwnUser', 'LocalIssuer']
}
}
},
{
- resource: Entity.USER, action: [Action.READ, Action.CREATE, Action.UPDATE],
+ resource: Entity.USER, action: [Action.READ, Action.CREATE],
+ attributes: [
+ 'id', 'name', 'firstName', 'email', 'role', 'status', 'issuer', 'locale', 'plateID',
+ 'notificationsActive', 'notifications', 'phone', 'mobile', 'iNumber', 'costCenter', 'address', 'technical', 'freeAccess'
+ ]
+ },
+ {
+ resource: Entity.USER, action: Action.UPDATE,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['LocalIssuer']
+ }
+ },
attributes: [
'id', 'name', 'firstName', 'email', 'role', 'status', 'issuer', 'locale', 'plateID',
'notificationsActive', 'notifications', 'phone', 'mobile', 'iNumber', 'costCenter', 'address', 'technical', 'freeAccess'
@@ -152,12 +180,29 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
{ resource: Entity.TAG, action: [Action.IMPORT, Action.EXPORT] },
{
resource: Entity.TAG, action: Action.READ,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['LocalIssuer'],
+ }
+ },
attributes: [
'id', 'userID', 'issuer', 'active', 'description', 'visualID', 'default', 'user.id',
'user.name', 'user.firstName', 'user.email'
]
},
- { resource: Entity.TAG, action: [Action.CREATE, Action.UPDATE, Action.DELETE] },
+ {
+ resource: Entity.TAG, action: [Action.UPDATE, Action.DELETE],
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['LocalIssuer'],
+ }
+ }
+ },
+ { resource: Entity.TAG, action: Action.CREATE },
{ resource: Entity.CHARGING_PROFILE, action: Action.LIST },
{ resource: Entity.CHARGING_PROFILE, action: [Action.READ] },
{
@@ -761,6 +806,13 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
},
{
resource: Entity.TAG, action: Action.ASSIGN,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: [],
+ filters: ['LocalIssuer']
+ }
+ },
attributes: [
'userID', 'description', 'visualID', 'default',
'user.name', 'user.firstName', 'user.email', 'createdOn', 'lastChangedOn'
@@ -988,7 +1040,7 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
],
},
{
- resource: Entity.USER, action: [Action.CREATE, Action.UPDATE],
+ resource: Entity.USER, action: Action.CREATE,
condition: {
Fn: 'custom:dynamicAuthorizations',
args: {
@@ -1001,6 +1053,20 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
'notificationsActive', 'notifications', 'phone', 'mobile', 'iNumber', 'costCenter', 'address', 'technical'
],
},
+ {
+ resource: Entity.USER, action: Action.UPDATE,
+ condition: {
+ Fn: 'custom:dynamicAuthorizations',
+ args: {
+ asserts: ['BasicUser'],
+ filters: ['SitesAdmin', 'LocalIssuer'],
+ }
+ },
+ attributes: [
+ 'id', 'name', 'firstName', 'email', 'role', 'status', 'issuer', 'locale', 'plateID',
+ 'notificationsActive', 'notifications', 'phone', 'mobile', 'iNumber', 'costCenter', 'address', 'technical'
+ ],
+ },
{ resource: Entity.USER, action: Action.SYNCHRONIZE_BILLING_USER },
{
resource: Entity.USER, action: Action.DELETE,
@@ -1008,7 +1074,7 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
Fn: 'custom:dynamicAuthorizations',
args: {
asserts: ['BasicUser'],
- filters: ['-OwnUser', 'SitesAdmin']
+ filters: ['-OwnUser', 'SitesAdmin', 'LocalIssuer']
}
}
},

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
@@ -223,9 +223,6 @@ export default class AuthorizationService {
}
public static async addUserAuthorizations(tenant: Tenant, userToken: UserToken, user: User, authorizationFilter: AuthorizationFilter): Promise<void> {
- if (!user.issuer) {
- user.canRead = true;
- } else {
user.canRead = true; // Always true as it should be filtered upfront
user.canUpdate = await AuthorizationService.canPerformAuthorizationAction(
tenant, userToken, Entity.USER, Action.UPDATE, authorizationFilter, { UserID: user.id }, user);
@@ -234,7 +231,6 @@ export default class AuthorizationService {
// Optimize data over the net
Utils.removeCanPropertiesWithFalseValue(user);
}
- }
public static async checkAndGetUsersAuthorizations(tenant: Tenant, userToken: UserToken,
filteredRequest: Partial<HttpUsersRequest>): Promise<AuthorizationFilter> {
@@ -340,9 +336,6 @@ export default class AuthorizationService {
}
public static async addTagAuthorizations(tenant: Tenant, userToken: UserToken, tag: Tag, authorizationFilter: AuthorizationFilter): Promise<void> {
- if (!tag.issuer) {
- tag.canRead = true;
- } else {
tag.canRead = true; // Always true as it should be filtered upfront
tag.canDelete = await AuthorizationService.canPerformAuthorizationAction(
tenant, userToken, Entity.TAG, Action.DELETE, authorizationFilter, { TagID: tag.id }, tag);
@@ -359,7 +352,6 @@ export default class AuthorizationService {
// Optimize data over the net
Utils.removeCanPropertiesWithFalseValue(tag);
}
- }
public static async checkAndGetRegistrationTokenAuthorizations(tenant: Tenant, userToken: UserToken,
filteredRequest: Partial<HttpRegistrationTokenRequest>, authAction: Action, entityData?: EntityData): Promise<AuthorizationFilter> {

MODIFY
src/server/rest/v1/service/UtilsService.ts
src/server/rest/v1/service/UtilsService.ts
@@ -115,6 +115,7 @@ export default class UtilsService {
UtilsService.assertObjectExists(action, chargingStation, `ChargingStation ID '${chargingStationID}' does not exist`,
MODULE_NAME, 'checkAndGetChargingStationAuthorization', userToken);
// External Charging Station
+ // TODO: require auth migration to remove below check -> checkAndGetChargingStationAuthorizations doesn't use auth definition !
if (!chargingStation.issuer) {
throw new AppError({
errorCode: HTTPError.GENERAL_ERROR,
@@ -315,6 +316,7 @@ export default class UtilsService {
UtilsService.assertObjectExists(action, user, `User ID '${userID}' does not exist`,
MODULE_NAME, 'checkAndGetUserAuthorization', userToken);
// External User
+ // TODO: need alignement of auth definition to remove below check
if (checkIssuer && !user.issuer) {
throw new AppError({
errorCode: HTTPError.GENERAL_ERROR,
@@ -546,18 +548,6 @@ export default class UtilsService {
module: MODULE_NAME, method: 'checkUserSitesAuthorization',
});
}
- for (const site of sites) {
- // External Site
- if (!site.issuer) {
- throw new AppError({
- errorCode: HTTPError.GENERAL_ERROR,
- message: `Site ID '${site.id}' not issued by the organization`,
- module: MODULE_NAME, method: 'checkUserSitesAuthorization',
- user: userToken,
- action: action
- });
- }
- }
return sites;
}
@@ -606,19 +596,6 @@ export default class UtilsService {
module: MODULE_NAME, method: 'checkSiteUsersAuthorization',
});
}
- for (const user of users) {
- // External User
- if (!user.issuer) {
- throw new AppError({
- errorCode: HTTPError.GENERAL_ERROR,
- message: `User ID '${user.id}' not issued by the organization`,
- module: MODULE_NAME, method: 'checkSiteUsersAuthorization',
- user: userToken,
- actionOnUser: user,
- action: action
- });
- }
- }
return users;
}
@@ -664,18 +641,6 @@ export default class UtilsService {
module: MODULE_NAME, method: 'checkSiteAreaAssetsAuthorization',
});
}
- for (const asset of assets) {
- // External Asset
- if (!asset.issuer) {
- throw new AppError({
- errorCode: HTTPError.GENERAL_ERROR,
- message: `Asset ID '${asset.id}' not issued by the organization`,
- module: MODULE_NAME, method: 'checkSiteAreaAssetsAuthorization',
- user: userToken,
- action: action
- });
- }
- }
return assets;
}
@@ -722,18 +687,6 @@ export default class UtilsService {
module: MODULE_NAME, method: 'checkSiteAreaChargingStationsAuthorization',
});
}
- for (const chargingStation of chargingStations) {
- // External Charging Station
- if (!chargingStation.issuer) {
- throw new AppError({
- errorCode: HTTPError.GENERAL_ERROR,
- message: `Charging Station ID '${chargingStation.id}' not issued by the organization`,
- module: MODULE_NAME, method: 'checkSiteAreaChargingStationsAuthorization',
- user: userToken,
- action: action
- });
- }
- }
return chargingStations;
}
@@ -888,15 +841,15 @@ export default class UtilsService {
}
public static async checkAndGetTagAuthorization(tenant: Tenant, userToken:UserToken, tagID: string, authAction: Action,
- action: ServerAction, entityData?: EntityData, additionalFilters: Record<string, any> = {}, applyProjectFields = false, checkIssuer = true): Promise<Tag> {
+ action: ServerAction, entityData?: EntityData, additionalFilters: Record<string, any> = {}, applyProjectFields = false): Promise<Tag> {
return UtilsService.checkAndGetTagByXXXAuthorization(tenant, userToken, tagID, TagStorage.getTag.bind(this),
- authAction, action, entityData, additionalFilters, applyProjectFields, checkIssuer);
+ authAction, action, entityData, additionalFilters, applyProjectFields);
}
public static async checkAndGetTagByVisualIDAuthorization(tenant: Tenant, userToken:UserToken, tagID: string, authAction: Action,
- action: ServerAction, entityData?: EntityData, additionalFilters: Record<string, any> = {}, applyProjectFields = false, checkIssuer = true): Promise<Tag> {
+ action: ServerAction, entityData?: EntityData, additionalFilters: Record<string, any> = {}, applyProjectFields = false): Promise<Tag> {
return UtilsService.checkAndGetTagByXXXAuthorization(tenant, userToken, tagID, TagStorage.getTagByVisualID.bind(this),
- authAction, action, entityData, additionalFilters, applyProjectFields, checkIssuer);
+ authAction, action, entityData, additionalFilters, applyProjectFields);
}
public static sendEmptyDataResult(res: Response, next: NextFunction): void {
@@ -1988,7 +1941,7 @@ export default class UtilsService {
private static async checkAndGetTagByXXXAuthorization(tenant: Tenant, userToken:UserToken, id: string,
getTagByXXX: (tenant: Tenant, id: string, params: any, projectedFileds: string[]) => Promise<Tag>, authAction: Action,
- action: ServerAction, entityData?: EntityData, additionalFilters: Record<string, any> = {}, applyProjectFields = false, checkIssuer = true): Promise<Tag> {
+ action: ServerAction, entityData?: EntityData, additionalFilters: Record<string, any> = {}, applyProjectFields = false): Promise<Tag> {
// Check mandatory fields
UtilsService.assertIdIsProvided(action, id, MODULE_NAME, 'checkAndGetTagByXXXAuthorization', userToken);
// Get dynamic auth
@@ -2013,17 +1966,6 @@ export default class UtilsService {
);
UtilsService.assertObjectExists(action, tag, `Tag ID '${id}' does not exist`,
MODULE_NAME, 'handleGetTag', userToken);
- // External Tag
- if (checkIssuer && !tag.issuer) {
- throw new AppError({
- errorCode: HTTPError.GENERAL_ERROR,
- message: `Tag ID '${tag.id}' not issued by the organization`,
- module: MODULE_NAME, method: 'checkAndGetTagByXXXAuthorization',
- user: userToken,
- action: action,
- detailedMessages: { tag }
- });
- }
// Assign projected fields
if (authorizationFilter.projectFields) {
tag.projectFields = authorizationFilter.projectFields;

MODIFY
src/storage/mongodb/TagStorage.ts
src/storage/mongodb/TagStorage.ts
@@ -240,25 +240,28 @@ export default class TagStorage {
}
public static async getTag(tenant: Tenant, id: string,
- params: { userIDs?: string[], withUser?: boolean; withNbrTransactions?: boolean; active?: boolean; siteIDs?: string[]; } = {}, projectFields?: string[]): Promise<Tag> {
+ params: { userIDs?: string[], withUser?: boolean, withNbrTransactions?: boolean, active?: boolean, siteIDs?: string[], issuer?: boolean } = {},
+ projectFields?: string[]): Promise<Tag> {
const tagMDB = await TagStorage.getTags(tenant, {
tagIDs: [id],
withUser: params.withUser,
withNbrTransactions: params.withNbrTransactions,
userIDs: params.userIDs,
active: params.active,
- siteIDs: params.siteIDs
+ siteIDs: params.siteIDs,
+ issuer: params.issuer,
}, Constants.DB_PARAMS_SINGLE_RECORD, projectFields);
return tagMDB.count === 1 ? tagMDB.result[0] : null;
}
public static async getTagByVisualID(tenant: Tenant, visualID: string,
- params: { withUser?: boolean; withNbrTransactions?: boolean, userIDs?: string[] } = {}, projectFields?: string[]): Promise<Tag> {
+ params: { withUser?: boolean, withNbrTransactions?: boolean, userIDs?: string[], issuer?: boolean } = {}, projectFields?: string[]): Promise<Tag> {
const tagMDB = await TagStorage.getTags(tenant, {
visualIDs: [visualID],
withUser: params.withUser,
withNbrTransactions: params.withNbrTransactions,
- userIDs: params.userIDs
+ userIDs: params.userIDs,
+ issuer: params.issuer
}, Constants.DB_PARAMS_SINGLE_RECORD, projectFields);
return tagMDB.count === 1 ? tagMDB.result[0] : null;
}

Small clean and refactor of authorizations

- Move issuer check in auth definition when possible
- Update Auth definition with issuer constraint on actions