Authorization alignments
MODIFY
src/authorization/AuthorizationsDefinition.ts
src/authorization/AuthorizationsDefinition.ts
@@ -121,9 +121,7 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
{ 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.COMPANY, action: Action.READ, attributes: ['*']
- },
+ { resource: Entity.COMPANY, action: Action.READ, attributes: ['*'] },
// -----------------------------------------------------------------------------------------------
// TODO - put it pack as soon as BILLING has been validated of SLF
// -----------------------------------------------------------------------------------------------
@@ -143,9 +141,7 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
{ resource: Entity.SITE_AREAS, action: Action.LIST, attributes: ['*'] },
{ resource: Entity.SITE_AREA, action: Action.READ, attributes: ['*'] },
{ resource: Entity.CHARGING_STATIONS, action: Action.LIST, attributes: ['*'] },
- {
- resource: Entity.CHARGING_STATION, action: [Action.READ], attributes: ['*']
- },
+ { resource: Entity.CHARGING_STATION, action: [Action.READ], attributes: ['*'] },
{
resource: Entity.CHARGING_STATION,
action: [Action.REMOTE_START_TRANSACTION, Action.AUTHORIZE, Action.START_TRANSACTION],
@@ -166,9 +162,7 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
]
}
},
- {
- resource: Entity.TAG, action: Action.READ, attributes: ['*']
- },
+ { resource: Entity.TAG, action: Action.READ, attributes: ['*'] },
{ resource: Entity.TAGS, action: Action.LIST, attributes: ['*'] },
{
resource: Entity.CHARGING_STATION,

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
-import { Action, AuthorizationFilter, Entity } from '../../../../types/Authorization';
import { CompanyDataResult, SiteAreaDataResult, SiteDataResult } from '../../../../types/DataResult';
import { HttpCompaniesRequest, HttpCompanyRequest } from '../../../../types/requests/HttpCompanyRequest';
import { HttpSiteAreaRequest, HttpSiteAreasRequest } from '../../../../types/requests/HttpSiteAreaRequest';
@@ -6,11 +5,10 @@ import { HttpSiteAssignUsersRequest, HttpSiteRequest, HttpSiteUsersRequest } fro
import { HttpTagsRequest, HttpUserAssignSitesRequest, HttpUserRequest, HttpUserSitesRequest, HttpUsersRequest } from '../../../../types/requests/HttpUserRequest';
import User, { UserRole } from '../../../../types/User';
-import AppAuthError from '../../../../exception/AppAuthError';
+import { AuthorizationFilter } from '../../../../types/Authorization';
import Authorizations from '../../../../authorization/Authorizations';
import Company from '../../../../types/Company';
import Constants from '../../../../utils/Constants';
-import { HTTPAuthError } from '../../../../types/HTTPError';
import HttpByIDRequest from '../../../../types/requests/HttpByIDRequest';
import { HttpChargingStationRequest } from '../../../../types/requests/HttpChargingStationRequest';
import { ServerAction } from '../../../../types/Server';
@@ -25,8 +23,6 @@ import UserToken from '../../../../types/UserToken';
import Utils from '../../../../utils/Utils';
import _ from 'lodash';
-const MODULE_NAME = 'AuthorizationService';
-
export default class AuthorizationService {
public static async checkAndGetSiteAuthorizationFilters(
tenant: Tenant, userToken: UserToken, filteredRequest: HttpSiteRequest): Promise<AuthorizationFilter> {
@@ -39,7 +35,8 @@ export default class AuthorizationService {
};
// Check Projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Not an Admin user?
if (userToken.role !== UserRole.ADMIN) {
@@ -52,37 +49,6 @@ export default class AuthorizationService {
return authorizationFilters;
}
- public static async checkAndGetUpdateSiteAuthorizationFilters(
- tenant: Tenant, userToken: UserToken, filteredRequest: HttpSiteRequest): Promise<AuthorizationFilter> {
- const authorizationFilters: AuthorizationFilter = {
- filters: {},
- projectFields: [
- 'id', 'name', 'issuer', 'image', 'address', 'companyID', 'company.name', 'autoUserSiteAssignment', 'public'
- ],
- authorized: userToken.role === UserRole.ADMIN,
- };
- // Check Projection
- if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
- }
- // Not an Admin user?
- if (userToken.role !== UserRole.ADMIN) {
- // Get SiteIDs for which user is Site Admin
- const { siteAdminIDs, siteOwnerIDs } = await AuthorizationService.getSiteAdminOwnerIDs(tenant, userToken);
- if (Utils.isEmptyArray(siteAdminIDs) || !siteAdminIDs.includes(filteredRequest.ID)) {
- throw new AppAuthError({
- errorCode: HTTPAuthError.FORBIDDEN,
- user: userToken,
- action: Action.UPDATE, entity: Entity.SITE,
- module: MODULE_NAME, method: 'checkAndGetUpdateSiteAuthorizationFilters',
- });
- } else {
- authorizationFilters.authorized = true;
- }
- }
- return authorizationFilters;
- }
-
public static async addSitesAuthorizations(tenant: Tenant, userToken: UserToken, sites: SiteDataResult): Promise<void> {
// Get Site Admins
const siteAdminIDs = await AuthorizationService.getSiteAdminSiteIDs(tenant.id, userToken);
@@ -129,7 +95,8 @@ export default class AuthorizationService {
}
// Check Projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Not an Admin?
if (userToken.role !== UserRole.ADMIN) {
@@ -164,7 +131,8 @@ export default class AuthorizationService {
};
// Check projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Handle Sites
await AuthorizationService.checkAssignedSiteAdmins(
@@ -183,7 +151,8 @@ export default class AuthorizationService {
};
// Check projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Handle Sites
await AuthorizationService.checkAssignedSiteAdmins(
@@ -272,7 +241,8 @@ export default class AuthorizationService {
};
// Check projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Get authorization filters from users
const usersAuthorizationFilters = await AuthorizationService.checkAndGetUsersAuthorizationFilters(tenant, userToken, filteredRequest);
@@ -309,7 +279,8 @@ export default class AuthorizationService {
};
// Check projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Handle Sites
await AuthorizationService.checkAssignedSiteAdmins(
@@ -329,7 +300,8 @@ export default class AuthorizationService {
};
// Check projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Handle Sites
await AuthorizationService.checkAssignedSiteAdmins(
@@ -353,7 +325,8 @@ export default class AuthorizationService {
}
// Check projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Handle Sites
await AuthorizationService.checkAssignedSiteAdmins(
@@ -370,7 +343,8 @@ export default class AuthorizationService {
};
// Check projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Handle Sites
await AuthorizationService.checkAssignedSiteAdmins(
@@ -418,7 +392,8 @@ export default class AuthorizationService {
}
// Check Projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Not an Admin?
if (userToken.role !== UserRole.ADMIN) {
@@ -482,7 +457,8 @@ export default class AuthorizationService {
};
// Check projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Not an Admin?
if (userToken.role !== UserRole.ADMIN) {
@@ -505,7 +481,8 @@ export default class AuthorizationService {
};
// Check Projection
if (!Utils.isEmptyArray(filteredRequest.ProjectFields)) {
- authorizationFilters.projectFields = authorizationFilters.projectFields.filter((projectField) => filteredRequest.ProjectFields.includes(projectField));
+ authorizationFilters.projectFields = authorizationFilters.projectFields.filter(
+ (projectField) => filteredRequest.ProjectFields.includes(projectField));
}
// Not an Admin?
if (userToken.role !== UserRole.ADMIN) {

MODIFY
src/server/rest/v1/service/SiteService.ts
src/server/rest/v1/service/SiteService.ts
@@ -504,6 +504,8 @@ export default class SiteService {
// Check mandatory fields
UtilsService.assertIdIsProvided(action, filteredRequest.id, MODULE_NAME, 'handleUpdateSite', req.user);
// Check auth
+ console.log(JSON.stringify(req.user, null, ' '));
+
if (!Authorizations.canUpdateSite(req.user)) {
throw new AppAuthError({
errorCode: HTTPAuthError.FORBIDDEN,
@@ -518,25 +520,9 @@ export default class SiteService {
// Check and Get Company
await UtilsService.checkAndGetCompanyAuthorization(
req.tenant, req.user, filteredRequest.companyID, 'handleUpdateSite', action, {});
- // Check dynamic auth
- const authorizationSiteFilters = await AuthorizationService.checkAndGetUpdateSiteAuthorizationFilters(
- req.tenant, req.user, { ID: filteredRequest.id });
- // Get Site & check it exists
- const site = await SiteStorage.getSite(
- req.user.tenantID, filteredRequest.id, authorizationSiteFilters.filters);
- UtilsService.assertObjectExists(action, site, `Site ID '${filteredRequest.id}' does not exist`,
- MODULE_NAME, 'handleUpdateSite', req.user);
- // External Site
- if (!site.issuer) {
- throw new AppError({
- source: Constants.CENTRAL_SERVER,
- errorCode: HTTPError.GENERAL_ERROR,
- message: `Site '${site.name}' with ID '${site.id}' not issued by the organization`,
- module: MODULE_NAME, method: 'handleUpdateSite',
- user: req.user,
- action: action
- });
- }
+ // Check and Get Site
+ const site = await UtilsService.checkAndGetSiteAuthorization(
+ req.tenant, req.user, filteredRequest.id, 'handleUpdateSite', action, {});
// Update
site.name = filteredRequest.name;
site.public = filteredRequest.public;

MODIFY
src/server/rest/v1/service/UtilsService.ts
src/server/rest/v1/service/UtilsService.ts
@@ -30,6 +30,7 @@ import Tag from '../../../../types/Tag';
import Tenant from '../../../../types/Tenant';
import TenantComponents from '../../../../types/TenantComponents';
import { TransactionInErrorType } from '../../../../types/InError';
+import UserStorage from '../../../../storage/mongodb/UserStorage';
import UserToken from '../../../../types/UserToken';
import Utils from '../../../../utils/Utils';
import countries from 'i18n-iso-countries';
@@ -148,6 +149,55 @@ export default class UtilsService {
return company;
}
+ public static async checkAndGetUserAuthorization(tenant: Tenant, userToken: UserToken, userID: string,
+ method: string, action: ServerAction, additionalFilters: Record<string, any>, applyProjectFields = false): Promise<User> {
+ // Check static auth for reading user
+ if (!Authorizations.canReadUser(userToken, userID)) {
+ throw new AppAuthError({
+ errorCode: HTTPAuthError.FORBIDDEN,
+ user: userToken,
+ action: Action.READ, entity: Entity.USER,
+ module: MODULE_NAME, method,
+ value: userID
+ });
+ }
+ // Check mandatory fields
+ UtilsService.assertIdIsProvided(action, userID, MODULE_NAME, method, userToken);
+ // Get dynamic auth
+ const authorizationFilter = await AuthorizationService.checkAndGetUserAuthorizationFilters(
+ tenant, userToken, { ID: userID });
+ if (!authorizationFilter.authorized) {
+ throw new AppAuthError({
+ errorCode: HTTPAuthError.FORBIDDEN,
+ user: userToken,
+ action: Action.READ, entity: Entity.USER,
+ module: MODULE_NAME, method,
+ });
+ }
+ // Get User
+ const user = await UserStorage.getUser(tenant.id, userID,
+ {
+ ...additionalFilters,
+ ...authorizationFilter.filters
+ },
+ applyProjectFields ? authorizationFilter.projectFields : null
+ );
+ UtilsService.assertObjectExists(action, user, `User ID '${userID}' does not exist`,
+ MODULE_NAME, method, userToken);
+ // External User
+ if (!user.issuer) {
+ throw new AppError({
+ source: Constants.CENTRAL_SERVER,
+ errorCode: HTTPError.GENERAL_ERROR,
+ message: `User '${user.name}' with ID '${user.id}' not issued by the organization`,
+ module: MODULE_NAME, method,
+ user: userToken,
+ action: action
+ });
+ }
+ return user;
+ }
+
public static async checkAndGetSiteAuthorization(tenant: Tenant, userToken: UserToken, siteID: string,
method: string, action: ServerAction, additionalFilters: Record<string, any>, applyProjectFields = false): Promise<Site> {
// Check static auth for reading site

Authorization alignments