Skip to content

Commit

Permalink
fix: add error handling to socket.data callback in case of validation…
Browse files Browse the repository at this point in the history
… of configuration failure
  • Loading branch information
LwveMike committed Apr 19, 2024
1 parent 5f0d822 commit 954cedc
Showing 1 changed file with 97 additions and 77 deletions.
174 changes: 97 additions & 77 deletions packages/tacacs-plus/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,40 +85,50 @@ export class Client {
socket.write(authorizationRequest.toBuffer())

socket.on('data', (data: Buffer) => {
const decodedPacket = Packet.decodePacket(data, this.#secret)

this.#logger.debug(`Received:\n${decodedPacket.toHumanReadable()}\n`)

const authorizationReply = AuthorizationReply.decode(decodedPacket)

switch (authorizationReply.status) {
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_FAIL: {
socket.destroy()
const error = new TacacsError('Authorization Failed', getNameFromCollectionValue(authorizationReply.status, AuthorizationReply.STATUSES))
this.#logger.error(error.message)
return reject(error)
}
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_PASS_REPL: {
this.#logger.log('PASS_REPL')
return resolve(authorizationReply.args)
}
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_PASS_ADD: {
this.#logger.log('PASS_ADD')
return resolve(authorizationReply.args)
}
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_ERROR: {
socket.destroy()
const error = new TacacsError('Authorization Errored', getNameFromCollectionValue(authorizationReply.status, AuthorizationReply.STATUSES))
this.#logger.error(error.message)
return reject(error)
try {
const decodedPacket = Packet.decodePacket(data, this.#secret)

this.#logger.debug(`Received:\n${decodedPacket.toHumanReadable()}\n`)

const authorizationReply = AuthorizationReply.decode(decodedPacket)

switch (authorizationReply.status) {
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_FAIL: {
socket.destroy()
const error = new TacacsError('Authorization Failed', getNameFromCollectionValue(authorizationReply.status, AuthorizationReply.STATUSES))
this.#logger.error(error.message)
return reject(error)
}
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_PASS_REPL: {
this.#logger.log('PASS_REPL')
return resolve(authorizationReply.args)
}
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_PASS_ADD: {
this.#logger.log('PASS_ADD')
return resolve(authorizationReply.args)
}
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_ERROR: {
socket.destroy()
const error = new TacacsError('Authorization Errored', getNameFromCollectionValue(authorizationReply.status, AuthorizationReply.STATUSES))
this.#logger.error(error.message)
return reject(error)
}
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_FOLLOW: {
return notImplemented('FOLLOW')
}
default: {
const error = new TacacsError('Unknown', 'Unknown')
reject(error)
}
}
case AuthorizationReply.STATUSES.TAC_PLUS_AUTHOR_STATUS_FOLLOW: {
return notImplemented('FOLLOW')
}
default: {
const error = new TacacsError('Unknown', 'Unknown')
reject(error)
}
catch (err: unknown) {
socket.destroy()
if (err instanceof Error) {
this.#logger.error(`Original error: ${err.message}`)
}

return reject(new Error('Invalid Tacacs+ configuration, client configuration or Packet validation'))
}
})
})
Expand Down Expand Up @@ -196,53 +206,63 @@ export class Client {
socket.write(authStartPacket.toBuffer())

socket.on('data', (data: Buffer) => {
const decodedPacket = Packet.decodePacket(data, this.#secret)

this.#logger.debug(`Received:\n${decodedPacket.toHumanReadable()}\n`)

const authenticationReply = new AuthenticationReply(decodedPacket.body, decodedPacket.header.length)

switch (authenticationReply.status) {
case AuthenticationReply.STATUSES.TAC_PLUS_AUTHEN_STATUS_GETPASS: {
const bodyBuffer = new AuthenticationContinue({ userMsg: password }).toBuffer()

const innerHeader = new Header({
majorVersion: Header.MAJOR_VERSIONS.TAC_PLUS_MAJOR_VER,
minorVersion,
type: Header.TYPES.TAC_PLUS_AUTHEN,
flags: (this.#secret === undefined ? Header.FLAGS.TAC_PLUS_UNENCRYPTED_FLAG : 0),
seqNo: getNextSeqNo(),
sessionId,
length: bodyBuffer.length,
})

const authContinuePacket = new Packet(innerHeader, bodyBuffer, this.#secret)

this.#logger.debug(`\nSent:\n${authContinuePacket.toHumanReadable()}\n`)

return socket.write(authContinuePacket.toBuffer())
try {
const decodedPacket = Packet.decodePacket(data, this.#secret)

this.#logger.debug(`Received:\n${decodedPacket.toHumanReadable()}\n`)

const authenticationReply = new AuthenticationReply(decodedPacket.body, decodedPacket.header.length)

switch (authenticationReply.status) {
case AuthenticationReply.STATUSES.TAC_PLUS_AUTHEN_STATUS_GETPASS: {
const bodyBuffer = new AuthenticationContinue({ userMsg: password }).toBuffer()

const innerHeader = new Header({
majorVersion: Header.MAJOR_VERSIONS.TAC_PLUS_MAJOR_VER,
minorVersion,
type: Header.TYPES.TAC_PLUS_AUTHEN,
flags: (this.#secret === undefined ? Header.FLAGS.TAC_PLUS_UNENCRYPTED_FLAG : 0),
seqNo: getNextSeqNo(),
sessionId,
length: bodyBuffer.length,
})

const authContinuePacket = new Packet(innerHeader, bodyBuffer, this.#secret)

this.#logger.debug(`\nSent:\n${authContinuePacket.toHumanReadable()}\n`)

return socket.write(authContinuePacket.toBuffer())
}
case AuthenticationReply.STATUSES.TAC_PLUS_AUTHEN_STATUS_PASS: {
socket.destroy()
this.#logger.log('Authentication PASS')
return resolve(true)
}
case AuthenticationReply.STATUSES.TAC_PLUS_AUTHEN_STATUS_FAIL: {
socket.destroy()
const error = new TacacsError('Authentication Failed', getNameFromCollectionValue(authenticationReply.status, AuthenticationReply.STATUSES))
this.#logger.error(error.message)
return reject(error)
}
case AuthenticationReply.STATUSES.TAC_PLUS_AUTHEN_STATUS_ERROR: {
socket.destroy()
const error = new TacacsError('Authentication Errored', getNameFromCollectionValue(authenticationReply.status, AuthenticationReply.STATUSES))
this.#logger.error(error.message)
return reject(error)
}
default: {
const error = new TacacsError('Unknown', 'Unknown')
reject(error)
}
}
case AuthenticationReply.STATUSES.TAC_PLUS_AUTHEN_STATUS_PASS: {
socket.destroy()
this.#logger.log('Authentication PASS')
return resolve(true)
}
case AuthenticationReply.STATUSES.TAC_PLUS_AUTHEN_STATUS_FAIL: {
socket.destroy()
const error = new TacacsError('Authentication Failed', getNameFromCollectionValue(authenticationReply.status, AuthenticationReply.STATUSES))
this.#logger.error(error.message)
return reject(error)
}
case AuthenticationReply.STATUSES.TAC_PLUS_AUTHEN_STATUS_ERROR: {
socket.destroy()
const error = new TacacsError('Authentication Errored', getNameFromCollectionValue(authenticationReply.status, AuthenticationReply.STATUSES))
this.#logger.error(error.message)
return reject(error)
}
default: {
const error = new TacacsError('Unknown', 'Unknown')
reject(error)
}
catch (err: unknown) {
socket.destroy()
if (err instanceof Error) {
this.#logger.error(`Original error: ${err.message}`)
}

return reject(new Error('Invalid Tacacs+ configuration, client configuration or Packet validation'))
}
})
})
Expand Down

0 comments on commit 954cedc

Please sign in to comment.