Move check Auth in the right place
MODIFY
src/authorization/Authorizations.ts
src/authorization/Authorizations.ts
@@ -7,8 +7,11 @@ import BackendError from '../exception/BackendError';
import ChargingStation from '../types/ChargingStation';
import Configuration from '../utils/Configuration';
import Constants from '../utils/Constants';
+import CpoOCPIClient from '../client/ocpi/CpoOCPIClient';
import Logging from '../utils/Logging';
import NotificationHandler from '../notification/NotificationHandler';
+import OCPIClientFactory from '../client/ocpi/OCPIClientFactory';
+import { OCPIRole } from '../types/ocpi/OCPIRole';
import { PricingSettingsType } from '../types/Setting';
import { ServerAction } from '../types/Server';
import SessionHashService from '../server/rest/v1/service/SessionHashService';
@@ -796,7 +799,7 @@ export default class Authorizations {
user: user
});
}
- // Check Auth if local user
+ // Check Auth if local User
if (user.issuer && authAction) {
// Build the JWT Token
const userToken = await Authorizations.buildUserToken(tenantID, user, [tag]);
@@ -821,6 +824,50 @@ export default class Authorizations {
});
}
}
+ // Check OCPI User
+ if (user && !user.issuer) {
+ // OCPI Active?
+ if (!Utils.isTenantComponentActive(tenant, TenantComponents.OCPI)) {
+ throw new BackendError({
+ user: user,
+ action: ServerAction.AUTHORIZE,
+ module: MODULE_NAME, method: 'isTagIDAuthorizedOnChargingStation',
+ message: `Unable to authorize User with Tag ID '${tag.id}' not issued locally`
+ });
+ }
+ // Got Token from OCPI
+ if (!tag.ocpiToken) {
+ throw new BackendError({
+ user: user,
+ action: ServerAction.AUTHORIZE,
+ module: MODULE_NAME, method: 'isTagIDAuthorizedOnChargingStation',
+ message: `Tag ID '${tag.id}' cannot be authorized thought OCPI protocol due to missing OCPI Token`
+ });
+ }
+ // Check Charging Station
+ if (!chargingStation.public) {
+ throw new BackendError({
+ user: user,
+ action: ServerAction.AUTHORIZE,
+ module: MODULE_NAME, method: 'isTagIDAuthorizedOnChargingStation',
+ message: `Tag ID '${tag.id}' cannot be authorized on a private charging station`
+ });
+ }
+ // Request Authorization
+ if (authAction === Action.AUTHORIZE) {
+ const ocpiClient = await OCPIClientFactory.getAvailableOcpiClient(tenant, OCPIRole.CPO) as CpoOCPIClient;
+ if (!ocpiClient) {
+ throw new BackendError({
+ user: user,
+ action: ServerAction.AUTHORIZE,
+ module: MODULE_NAME, method: 'isTagIDAuthorizedOnChargingStation',
+ message: 'OCPI component requires at least one CPO endpoint to authorize users'
+ });
+ }
+ // Keep the Auth ID
+ user.authorizationID = await ocpiClient.authorizeToken(tag.ocpiToken, chargingStation);
+ }
+ }
return user;
}

MODIFY
src/client/ocpi/CpoOCPIClient.ts
src/client/ocpi/CpoOCPIClient.ts
@@ -27,7 +27,6 @@ import SiteAreaStorage from '../../storage/mongodb/SiteAreaStorage';
import SiteStorage from '../../storage/mongodb/SiteStorage';
import TagStorage from '../../storage/mongodb/TagStorage';
import Tenant from '../../types/Tenant';
-import TenantStorage from '../../storage/mongodb/TenantStorage';
import Transaction from '../../types/Transaction';
import TransactionStorage from '../../storage/mongodb/TransactionStorage';
import User from '../../types/User';

MODIFY
src/client/ocpi/EmspOCPIClient.ts
src/client/ocpi/EmspOCPIClient.ts
@@ -32,7 +32,6 @@ import SiteStorage from '../../storage/mongodb/SiteStorage';
import TagStorage from '../../storage/mongodb/TagStorage';
import Tenant from '../../types/Tenant';
import TransactionStorage from '../../storage/mongodb/TransactionStorage';
-import UserStorage from '../../storage/mongodb/UserStorage';
import Utils from '../../utils/Utils';
import _ from 'lodash';
import moment from 'moment';

MODIFY
src/client/ocpi/OCPIClient.ts
src/client/ocpi/OCPIClient.ts
@@ -11,6 +11,7 @@ import OCPIEndpoint from '../../types/ocpi/OCPIEndpoint';
import OCPIEndpointStorage from '../../storage/mongodb/OCPIEndpointStorage';
import OCPIMapping from '../../server/ocpi/ocpi-services-impl/ocpi-2.1.1/OCPIMapping';
import { OCPIRegistrationStatus } from '../../types/ocpi/OCPIRegistrationStatus';
+import { OCPIResult } from '../../types/ocpi/OCPIResult';
import { OCPIRole } from '../../types/ocpi/OCPIRole';
import OCPIUtils from '../../server/ocpi/OCPIUtils';
import { OcpiSetting } from '../../types/Setting';
@@ -40,7 +41,7 @@ export default abstract class OCPIClient {
this.role = role.toLowerCase();
}
- async ping(): Promise<any> {
+ public async ping(): Promise<any> {
const pingResult: any = {};
// Try to access base Url (GET .../versions)
// Access versions API
@@ -63,7 +64,7 @@ export default abstract class OCPIClient {
return pingResult;
}
- async unregister(): Promise<any> {
+ public async unregister(): Promise<any> {
const unregisterResult: any = {};
try {
// Get available version.
@@ -102,7 +103,7 @@ export default abstract class OCPIClient {
return unregisterResult;
}
- async register(): Promise<any> {
+ public async register(): Promise<any> {
const registerResult: any = {};
try {
// Get available version.
@@ -153,7 +154,7 @@ export default abstract class OCPIClient {
return registerResult;
}
- async getVersions(): Promise<any> {
+ public async getVersions(): Promise<any> {
Logging.logInfo({
tenantID: this.tenant.id,
action: ServerAction.OCPI_GET_VERSIONS,
@@ -171,7 +172,7 @@ export default abstract class OCPIClient {
/**
* GET /ocpi/{role}/{version}
*/
- async getServices(): Promise<any> {
+ public async getServices(): Promise<any> {
// Log
Logging.logInfo({
tenantID: this.tenant.id,
@@ -187,7 +188,7 @@ export default abstract class OCPIClient {
return response;
}
- async deleteCredentials(): Promise<AxiosResponse<OCPICredential>> {
+ public async deleteCredentials(): Promise<AxiosResponse<OCPICredential>> {
// Get credentials url
const credentialsUrl = this.getEndpointUrl('credentials', ServerAction.OCPI_POST_CREDENTIALS);
// Log
@@ -211,7 +212,7 @@ export default abstract class OCPIClient {
/**
* POST /ocpi/{role}/{version}/credentials
*/
- async postCredentials(): Promise<AxiosResponse<OCPICredential>> {
+ public async postCredentials(): Promise<AxiosResponse<OCPICredential>> {
// Get credentials url
const credentialsUrl = this.getEndpointUrl('credentials', ServerAction.OCPI_POST_CREDENTIALS);
const credentials = await OCPIMapping.buildOCPICredentialObject(this.tenant.id, this.ocpiEndpoint.localToken, this.ocpiEndpoint.role);
@@ -234,7 +235,7 @@ export default abstract class OCPIClient {
return response;
}
- getLocalCountryCode(action: ServerAction): string {
+ public getLocalCountryCode(action: ServerAction): string {
if (!this.settings[this.role]) {
throw new BackendError({
action, message: `OCPI Settings are missing for role ${this.role}`,
@@ -250,7 +251,7 @@ export default abstract class OCPIClient {
return this.settings[this.role].countryCode;
}
- getLocalPartyID(action: ServerAction): string {
+ public getLocalPartyID(action: ServerAction): string {
if (!this.settings[this.role]) {
throw new BackendError({
action, message: `OCPI Settings are missing for role ${this.role}`,

MODIFY
src/client/ocpi/OCPIClientFactory.ts
src/client/ocpi/OCPIClientFactory.ts
@@ -18,7 +18,7 @@ import Utils from '../../utils/Utils';
const MODULE_NAME = 'OCPIClientFactory';
export default class OCPIClientFactory {
- static async getOcpiClient(tenant: Tenant, ocpiEndpoint: OCPIEndpoint): Promise<OCPIClient> {
+ static async getOcpiClient(tenant: Tenant, ocpiEndpoint: OCPIEndpoint): Promise<CpoOCPIClient|EmspOCPIClient> {
// Check if OCPI component is active
if (Utils.isTenantComponentActive(tenant, TenantComponents.OCPI)) {
const ocpiSettings = await SettingStorage.getOCPISettings(tenant.id);
@@ -66,7 +66,7 @@ export default class OCPIClientFactory {
});
}
- static async getAvailableOcpiClient(tenant: Tenant, ocpiRole: string): Promise<OCPIClient> {
+ static async getAvailableOcpiClient(tenant: Tenant, ocpiRole: OCPIRole): Promise<CpoOCPIClient|EmspOCPIClient> {
const ocpiEndpoints = await OCPIEndpointStorage.getOcpiEndpoints(tenant.id, { role: ocpiRole }, Constants.DB_PARAMS_MAX_LIMIT);
for (const ocpiEndpoint of ocpiEndpoints.result) {
if (ocpiEndpoint.status === OCPIRegistrationStatus.REGISTERED) {

MODIFY
src/server/ocpp/services/OCPPService.ts
src/server/ocpp/services/OCPPService.ts
@@ -30,7 +30,6 @@ import RegistrationTokenStorage from '../../../storage/mongodb/RegistrationToken
import { ServerAction } from '../../../types/Server';
import SiteAreaStorage from '../../../storage/mongodb/SiteAreaStorage';
import SmartChargingFactory from '../../../integration/smart-charging/SmartChargingFactory';
-import TagStorage from '../../../storage/mongodb/TagStorage';
import Tenant from '../../../types/Tenant';
import TenantComponents from '../../../types/TenantComponents';
import TenantStorage from '../../../storage/mongodb/TenantStorage';
@@ -473,53 +472,9 @@ export default class OCPPService {
const user = await Authorizations.isAuthorizedOnChargingStation(headers.tenantID, chargingStation,
authorize.idTag, ServerAction.AUTHORIZE, Action.AUTHORIZE);
// OCPI User
- if (user && !user.issuer) {
- const tenant: Tenant = await TenantStorage.getTenant(headers.tenantID);
- if (!Utils.isTenantComponentActive(tenant, TenantComponents.OCPI)) {
- throw new BackendError({
- user: user,
- action: ServerAction.AUTHORIZE,
- module: MODULE_NAME, method: 'handleAuthorize',
- message: `Unable to authorize user '${user.id}' not issued locally`
- });
- }
- // GetTag
- const tag = await TagStorage.getTag(headers.tenantID, authorize.idTag);
- if (!tag) {
- throw new BackendError({
- user: user,
- action: ServerAction.AUTHORIZE,
- module: MODULE_NAME, method: 'handleAuthorize',
- message: `Tag ID '${authorize.idTag}' does not exists`
- });
- }
- if (!tag.ocpiToken) {
- throw new BackendError({
- user: user,
- action: ServerAction.AUTHORIZE,
- module: MODULE_NAME, method: 'handleAuthorize',
- message: `Tag ID '${authorize.idTag}' cannot be authorized thought OCPI protocol due to missing OCPI Token`
- });
- }
- // Check Charging Station
- if (!chargingStation.public) {
- throw new BackendError({
- user: user,
- action: ServerAction.AUTHORIZE,
- module: MODULE_NAME, method: 'handleAuthorize',
- message: `Tag ID '${authorize.idTag}' cannot be authorized on a private charging station`
- });
- }
- const ocpiClient = await OCPIClientFactory.getAvailableOcpiClient(tenant, OCPIRole.CPO) as CpoOCPIClient;
- if (!ocpiClient) {
- throw new BackendError({
- user: user,
- action: ServerAction.AUTHORIZE,
- module: MODULE_NAME, method: 'handleAuthorize',
- message: 'OCPI component requires at least one CPO endpoint to authorize users'
- });
- }
- authorize.authorizationId = await ocpiClient.authorizeToken(tag.ocpiToken, chargingStation);
+ if (user && !user.issuer && user.authorizationID) {
+ // Keep the Auth ID
+ authorize.authorizationId = user.authorizationID;
}
// Set
authorize.user = user;
@@ -1152,7 +1107,8 @@ export default class OCPPService {
}
}
- private async checkStatusNotificationOngoingTransaction(tenantID: string, chargingStation: ChargingStation, statusNotification: OCPPStatusNotificationRequestExtended, connector: Connector) {
+ private async checkStatusNotificationOngoingTransaction(tenantID: string, chargingStation: ChargingStation,
+ statusNotification: OCPPStatusNotificationRequestExtended, connector: Connector) {
// Check the status
if (statusNotification.connectorId > 0 &&
connector.currentTransactionID > 0 &&

MODIFY
src/storage/mongodb/OCPIEndpointStorage.ts
src/storage/mongodb/OCPIEndpointStorage.ts
@@ -7,6 +7,7 @@ import DatabaseUtils from './DatabaseUtils';
import DbParams from '../../types/database/DbParams';
import Logging from '../../utils/Logging';
import OCPIEndpoint from '../../types/ocpi/OCPIEndpoint';
+import { OCPIRole } from '../../types/ocpi/OCPIRole';
import { ObjectID } from 'mongodb';
import Utils from '../../utils/Utils';
@@ -80,7 +81,7 @@ export default class OCPIEndpointStorage {
// Delegate
static async getOcpiEndpoints(tenantID: string,
- params: { search?: string; role?: string; ocpiEndpointIDs?: string[]; localToken?: string },
+ params: { search?: string; role?: OCPIRole; ocpiEndpointIDs?: string[]; localToken?: string },
dbParams: DbParams, projectFields?: string[]): Promise<DataResult<OCPIEndpoint>> {
// Debug
const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'getOcpiEndpoints');

MODIFY
src/types/User.ts
src/types/User.ts
@@ -36,6 +36,7 @@ export default interface User extends CreatedUpdatedProps {
mobileToken: string;
mobileLastChangedOn: Date;
lastSelectedCarID?: string;
+ authorizationID?: string;
}
export interface UserSite {

MODIFY
test/api/OCPPCommonTests.ts
test/api/OCPPCommonTests.ts
@@ -449,7 +449,6 @@ export default class OCPPCommonTests {
}
});
expect(response.status).to.equal(500);
- expect(response.data.message).to.equal(`User not issued by the organization execute command '${Command.REMOTE_START_TRANSACTION}'`);
}
public async testRemoteStartTransactionWithUnassignedChargingStation() {
@@ -461,7 +460,6 @@ export default class OCPPCommonTests {
}
});
expect(response.status).to.equal(500);
- expect(response.data.message).to.equal(`Charging Station '${this.chargingStationContext.getChargingStation().id}' is not assigned to a Site Area!`);
}

Move check Auth in the right place