316 lines
9.4 KiB
TypeScript
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);
|
|
}
|
|
}
|