Files
smartregistry/ts/core/classes.authmanager.ts

316 lines
9.4 KiB
TypeScript

import type { IAuthConfig, IAuthToken, ICredentials, TRegistryProtocol } from './interfaces.core.js';
import type { IAuthProvider, ITokenOptions } from './interfaces.auth.js';
import { DefaultAuthProvider } from './classes.defaultauthprovider.js';
/**
* Unified authentication manager for all registry protocols.
* Delegates to a pluggable IAuthProvider for actual auth operations.
*
* @example
* ```typescript
* // Use default in-memory provider
* const auth = new AuthManager(config);
*
* // Use custom provider (LDAP, OAuth, etc.)
* const auth = new AuthManager(config, new LdapAuthProvider(ldapClient));
* ```
*/
export class AuthManager {
private provider: IAuthProvider;
constructor(
private config: IAuthConfig,
provider?: IAuthProvider
) {
// Use provided provider or default in-memory implementation
this.provider = provider || new DefaultAuthProvider(config);
}
/**
* Initialize the auth manager
*/
public async init(): Promise<void> {
if (this.provider.init) {
await this.provider.init();
}
}
// ========================================================================
// UNIFIED AUTHENTICATION (Delegated to Provider)
// ========================================================================
/**
* Authenticate user credentials
* @param credentials - Username and password
* @returns User ID or null
*/
public async authenticate(credentials: ICredentials): Promise<string | null> {
return this.provider.authenticate(credentials);
}
/**
* Validate any token (NPM, Maven, OCI, PyPI, RubyGems, Composer, Cargo)
* @param tokenString - Token string (UUID or JWT)
* @param protocol - Expected protocol type (optional, improves performance)
* @returns Auth token object or null
*/
public async validateToken(
tokenString: string,
protocol?: TRegistryProtocol
): Promise<IAuthToken | null> {
return this.provider.validateToken(tokenString, protocol);
}
/**
* Check if token has permission for an action
* @param token - Auth token (or null for anonymous)
* @param resource - Resource being accessed (e.g., "npm:package:foo")
* @param action - Action being performed (read, write, push, pull, delete)
* @returns true if authorized
*/
public async authorize(
token: IAuthToken | null,
resource: string,
action: string
): Promise<boolean> {
return this.provider.authorize(token, resource, action);
}
// ========================================================================
// NPM AUTHENTICATION
// ========================================================================
/**
* Create an NPM token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns NPM UUID token
*/
public async createNpmToken(userId: string, readonly: boolean = false): Promise<string> {
if (!this.config.npmTokens.enabled) {
throw new Error('NPM tokens are not enabled');
}
return this.provider.createToken(userId, 'npm', { readonly });
}
/**
* Validate an NPM token
* @param token - NPM UUID token
* @returns Auth token object or null
*/
public async validateNpmToken(token: string): Promise<IAuthToken | null> {
return this.provider.validateToken(token, 'npm');
}
/**
* Revoke an NPM token
* @param token - NPM UUID token
*/
public async revokeNpmToken(token: string): Promise<void> {
return this.provider.revokeToken(token);
}
/**
* List all tokens for a user
* @param userId - User ID
* @returns List of token info (without actual token values)
*/
public async listUserTokens(userId: string): Promise<Array<{
key: string;
readonly: boolean;
created: string;
protocol?: TRegistryProtocol;
}>> {
if (this.provider.listUserTokens) {
return this.provider.listUserTokens(userId);
}
return [];
}
// ========================================================================
// OCI AUTHENTICATION (JWT)
// ========================================================================
/**
* Create an OCI JWT token
* @param userId - User ID
* @param scopes - Permission scopes
* @param expiresIn - Expiration time in seconds
* @returns JWT token string
*/
public async createOciToken(
userId: string,
scopes: string[],
expiresIn: number = 3600
): Promise<string> {
if (!this.config.ociTokens?.enabled) {
throw new Error('OCI tokens are not enabled');
}
return this.provider.createToken(userId, 'oci', { scopes, expiresIn });
}
/**
* Validate an OCI JWT token
* @param jwt - JWT token string
* @returns Auth token object or null
*/
public async validateOciToken(jwt: string): Promise<IAuthToken | null> {
return this.provider.validateToken(jwt, 'oci');
}
// ========================================================================
// MAVEN AUTHENTICATION
// ========================================================================
/**
* Create a Maven token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns Maven UUID token
*/
public async createMavenToken(userId: string, readonly: boolean = false): Promise<string> {
return this.provider.createToken(userId, 'maven', { readonly });
}
/**
* Validate a Maven token
* @param token - Maven UUID token
* @returns Auth token object or null
*/
public async validateMavenToken(token: string): Promise<IAuthToken | null> {
return this.provider.validateToken(token, 'maven');
}
/**
* Revoke a Maven token
* @param token - Maven UUID token
*/
public async revokeMavenToken(token: string): Promise<void> {
return this.provider.revokeToken(token);
}
// ========================================================================
// COMPOSER TOKEN MANAGEMENT
// ========================================================================
/**
* Create a Composer token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns Composer UUID token
*/
public async createComposerToken(userId: string, readonly: boolean = false): Promise<string> {
return this.provider.createToken(userId, 'composer', { readonly });
}
/**
* Validate a Composer token
* @param token - Composer UUID token
* @returns Auth token object or null
*/
public async validateComposerToken(token: string): Promise<IAuthToken | null> {
return this.provider.validateToken(token, 'composer');
}
/**
* Revoke a Composer token
* @param token - Composer UUID token
*/
public async revokeComposerToken(token: string): Promise<void> {
return this.provider.revokeToken(token);
}
// ========================================================================
// CARGO TOKEN MANAGEMENT
// ========================================================================
/**
* Create a Cargo token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns Cargo UUID token
*/
public async createCargoToken(userId: string, readonly: boolean = false): Promise<string> {
return this.provider.createToken(userId, 'cargo', { readonly });
}
/**
* Validate a Cargo token
* @param token - Cargo UUID token
* @returns Auth token object or null
*/
public async validateCargoToken(token: string): Promise<IAuthToken | null> {
return this.provider.validateToken(token, 'cargo');
}
/**
* Revoke a Cargo token
* @param token - Cargo UUID token
*/
public async revokeCargoToken(token: string): Promise<void> {
return this.provider.revokeToken(token);
}
// ========================================================================
// PYPI AUTHENTICATION
// ========================================================================
/**
* Create a PyPI token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns PyPI UUID token
*/
public async createPypiToken(userId: string, readonly: boolean = false): Promise<string> {
return this.provider.createToken(userId, 'pypi', { readonly });
}
/**
* Validate a PyPI token
* @param token - PyPI UUID token
* @returns Auth token object or null
*/
public async validatePypiToken(token: string): Promise<IAuthToken | null> {
return this.provider.validateToken(token, 'pypi');
}
/**
* Revoke a PyPI token
* @param token - PyPI UUID token
*/
public async revokePypiToken(token: string): Promise<void> {
return this.provider.revokeToken(token);
}
// ========================================================================
// RUBYGEMS AUTHENTICATION
// ========================================================================
/**
* Create a RubyGems token
* @param userId - User ID
* @param readonly - Whether the token is readonly
* @returns RubyGems UUID token
*/
public async createRubyGemsToken(userId: string, readonly: boolean = false): Promise<string> {
return this.provider.createToken(userId, 'rubygems', { readonly });
}
/**
* Validate a RubyGems token
* @param token - RubyGems UUID token
* @returns Auth token object or null
*/
public async validateRubyGemsToken(token: string): Promise<IAuthToken | null> {
return this.provider.validateToken(token, 'rubygems');
}
/**
* Revoke a RubyGems token
* @param token - RubyGems UUID token
*/
public async revokeRubyGemsToken(token: string): Promise<void> {
return this.provider.revokeToken(token);
}
}