import type { AuthConfiguration } from '../types/AuthTypes.js'
import { OCPPVersion } from '../../../../types/ocpp/OCPPVersion.js'
+import { InMemoryAuthCache } from '../cache/InMemoryAuthCache.js'
import { AuthConfigValidator } from '../utils/ConfigValidator.js'
/**
}
/**
- * Create authorization cache (delegated to service implementation)
+ * Create authorization cache with rate limiting
* @param config - Authentication configuration
- * @returns undefined (cache creation delegated to service)
+ * @returns AuthCache instance with configured TTL and rate limiting
*/
- static createAuthCache (config: AuthConfiguration): undefined {
- // Cache creation is delegated to OCPPAuthServiceImpl
- // This method exists for API completeness
- return undefined
+ static createAuthCache (config: AuthConfiguration): AuthCache {
+ return new InMemoryAuthCache({
+ defaultTtl: config.authorizationCacheLifetime ?? 3600,
+ maxEntries: config.maxCacheEntries ?? 1000,
+ rateLimit: {
+ enabled: true,
+ maxRequests: 10, // 10 requests per minute per identifier
+ windowMs: 60000, // 1 minute window
+ },
+ })
}
/**
/** Local authorization usage rate */
localUsageRate: number
+ /** Rate limiting statistics */
+ rateLimit?: {
+ /** Number of requests blocked by rate limiting */
+ blockedRequests: number
+
+ /** Number of identifiers currently rate-limited */
+ rateLimitedIdentifiers: number
+
+ /** Total rate limit checks performed */
+ totalChecks: number
+ }
+
/** Remote authorization success rate */
remoteSuccessRate: number
}
export interface CacheStats {
+ /** Number of entries evicted due to capacity limits */
+ evictions: number
+
/** Expired entries count */
expiredEntries: number
/**
* Get authentication statistics
+ * @returns Authentication statistics including cache and rate limiting metrics
*/
- public getStats (): Promise<AuthStats> {
+ public async getStats (): Promise<AuthStats> {
const avgResponseTime =
this.metrics.totalRequests > 0
? this.metrics.totalResponseTime / this.metrics.totalRequests
? this.metrics.successfulAuth / this.metrics.remoteAuthCount
: 0
- return Promise.resolve({
+ // Get rate limiting stats from cache via remote strategy
+ let rateLimitStats:
+ | undefined
+ | { blockedRequests: number; rateLimitedIdentifiers: number; totalChecks: number }
+ const remoteStrategy = this.strategies.get('remote')
+ if (remoteStrategy?.getStats) {
+ const strategyStats = await remoteStrategy.getStats()
+ if ('cache' in strategyStats) {
+ const cacheStats = strategyStats.cache as {
+ rateLimit?: {
+ blockedRequests: number
+ rateLimitedIdentifiers: number
+ totalChecks: number
+ }
+ }
+ rateLimitStats = cacheStats.rateLimit
+ }
+ }
+
+ return {
avgResponseTime: Math.round(avgResponseTime * 100) / 100,
cacheHitRate: Math.round(cacheHitRate * 10000) / 100,
failedAuth: this.metrics.failedAuth,
lastUpdated: this.metrics.lastReset,
localUsageRate: Math.round(localUsageRate * 10000) / 100,
+ rateLimit: rateLimitStats,
remoteSuccessRate: Math.round(remoteSuccessRate * 10000) / 100,
successfulAuth: this.metrics.successfulAuth,
totalRequests: this.metrics.totalRequests,
- })
+ }
}
/**
})
await describe('createAuthCache', async () => {
- await it('should return undefined (delegated to service)', () => {
+ await it('should create InMemoryAuthCache instance', () => {
const config: AuthConfiguration = {
allowOfflineTxForUnknownId: false,
authorizationCacheEnabled: true,
const result = AuthComponentFactory.createAuthCache(config)
- expect(result).toBeUndefined()
+ expect(result).toBeDefined()
+ expect(result).toHaveProperty('get')
+ expect(result).toHaveProperty('set')
+ expect(result).toHaveProperty('clear')
+ expect(result).toHaveProperty('getStats')
})
})