diff --git a/.env.example b/.env.example index 12dd2928..2c4c0092 100644 --- a/.env.example +++ b/.env.example @@ -40,4 +40,4 @@ PERMANENT_API_BASE_PATH=${LOCAL_TEMPORARY_AUTH_TOKEN} # See https://fusionauth.io/docs/v1/tech/apis/api-keys FUSION_AUTH_HOST=${FUSION_AUTH_HOST} FUSION_AUTH_KEY=${FUSION_AUTH_KEY} -FUSION_AUTH_APP_ID=${FUSION_AUTH_APP_ID} +FUSION_AUTH_SFTP_APP_ID=${FUSION_AUTH_SFTP_APP_ID} diff --git a/src/classes/AuthenticationSession.ts b/src/classes/AuthenticationSession.ts index 666dae14..69210477 100644 --- a/src/classes/AuthenticationSession.ts +++ b/src/classes/AuthenticationSession.ts @@ -13,6 +13,8 @@ enum FusionAuthStatusCode { } export class AuthenticationSession { + private static readonly sftpFusionAuthAppId = process.env.FUSION_AUTH_SFTP_APP_ID ?? ''; + public authToken = ''; public refreshToken = ''; @@ -23,8 +25,6 @@ export class AuthenticationSession { private readonly fusionAuthClient; - private readonly fusionAuthAppId = process.env.FUSION_AUTH_APP_ID ?? ''; - private twoFactorId = ''; private twoFactorMethods: TwoFactorMethod[] = []; @@ -78,13 +78,12 @@ export class AuthenticationSession { private processPasswordResponse([password]: string[]): void { this.fusionAuthClient.login({ - applicationId: this.fusionAuthAppId, + applicationId: AuthenticationSession.sftpFusionAuthAppId, loginId: this.authContext.username, password, }).then((clientResponse) => { switch (clientResponse.statusCode) { - case FusionAuthStatusCode.Success: - case FusionAuthStatusCode.SuccessButUnregisteredInApp: + case FusionAuthStatusCode.Success: { if (clientResponse.response.token !== undefined) { logger.verbose('Successful password authentication attempt.', { username: this.authContext.username, @@ -93,11 +92,22 @@ export class AuthenticationSession { this.authTokenExpiresAt = clientResponse.response.tokenExpirationInstant ?? 0; this.refreshToken = clientResponse.response.refreshToken ?? ''; this.authContext.accept(); - return; + } else { + this.authContext.reject(); } - this.authContext.reject(); return; - case FusionAuthStatusCode.SuccessNeedsTwoFactorAuth: + } + case FusionAuthStatusCode.SuccessButUnregisteredInApp: { + const userId: string = clientResponse.response.user?.id ?? ''; + this.registerUserInApp(userId) + .then(() => { this.processPasswordResponse([password]); }) + .catch((error) => { + logger.warn('Error during registration and authentication:', error); + this.authContext.reject(); + }); + return; + } + case FusionAuthStatusCode.SuccessNeedsTwoFactorAuth: { if (clientResponse.response.twoFactorId !== undefined) { logger.verbose('Successful password authentication attempt; MFA required.', { username: this.authContext.username, @@ -105,16 +115,18 @@ export class AuthenticationSession { this.twoFactorId = clientResponse.response.twoFactorId; this.twoFactorMethods = clientResponse.response.methods ?? []; this.promptForTwoFactorMethod(); - return; + } else { + this.authContext.reject(); } - this.authContext.reject(); return; - default: + } + default: { logger.verbose('Failed password authentication attempt.', { username: this.authContext.username, response: clientResponse.response, }); this.authContext.reject(); + } } }).catch((clientResponse: unknown) => { const message = isPartialClientResponse(clientResponse) @@ -125,6 +137,29 @@ export class AuthenticationSession { }); } + private async registerUserInApp(userId: string): Promise { + return this.fusionAuthClient.register(userId, { + registration: { + applicationId: AuthenticationSession.sftpFusionAuthAppId, + }, + }).then((clientResponse) => { + switch (clientResponse.statusCode) { + case FusionAuthStatusCode.Success: + logger.verbose('User registered successfully after authentication.', { + userId, + }); + break; + default: + logger.verbose('User registration after authentication failed.', { + userId, + response: clientResponse.response, + }); + } + }).catch((error) => { + logger.warn('Error during user registration after authentication:', error); + }); + } + private promptForTwoFactorMethod(): void { const promptOptions = this.twoFactorMethods.map( (method, index) => `[${index + 1}] ${method.method ?? ''}`,