feat(java-client): operator credentials on acknowledge-alarm
Claude-Session: https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT
This commit is contained in:
+12
-3
@@ -273,6 +273,11 @@ public final class MxGatewayClient implements AutoCloseable {
|
||||
* worker's MXAccess session; the resulting native MxStatus is returned
|
||||
* in the reply. Acks are idempotent at the MxAccess layer.
|
||||
*
|
||||
* <p>{@code operator_user} is required; the gateway authenticates it with
|
||||
* {@code operator_password} (and optional {@code operator_domain}) and the
|
||||
* Historian records that operator. An empty password is allowed. The
|
||||
* password is scrubbed from any exception this method throws.
|
||||
*
|
||||
* @param request the {@code AcknowledgeAlarmRequest}
|
||||
* @return the raw acknowledge reply
|
||||
* @throws MxGatewayException on transport or protocol failure
|
||||
@@ -283,10 +288,14 @@ public final class MxGatewayClient implements AutoCloseable {
|
||||
MxGatewayErrors.ensureProtocolSuccess("acknowledge alarm", reply.getProtocolStatus(), null);
|
||||
return reply;
|
||||
} catch (RuntimeException error) {
|
||||
if (error instanceof MxGatewayException) {
|
||||
throw error;
|
||||
MxGatewayException mapped = error instanceof MxGatewayException gatewayError
|
||||
? gatewayError
|
||||
: (MxGatewayException) MxGatewayErrors.fromGrpc("acknowledge alarm", error);
|
||||
String secret = request.getOperatorPassword();
|
||||
if (secret.isEmpty()) {
|
||||
throw mapped;
|
||||
}
|
||||
throw MxGatewayErrors.fromGrpc("acknowledge alarm", error);
|
||||
throw MxGatewayErrors.redacted(mapped, secret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
@@ -28,6 +28,43 @@ final class MxGatewayErrors {
|
||||
return new MxGatewayException("gateway " + operation + " failed: " + error.getMessage(), error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds a gateway exception with an exact secret scrubbed from its
|
||||
* message and protocol status. The original is not chained as a cause
|
||||
* because its message and cause chain may carry the secret.
|
||||
*/
|
||||
static MxGatewayException redacted(MxGatewayException error, String secret) {
|
||||
String message = MxGatewaySecrets.redactExact(error.getMessage(), secret);
|
||||
if (error instanceof MxAccessException ex) {
|
||||
return new MxAccessException(message, scrub(ex.protocolStatus(), secret), ex.reply(), null);
|
||||
}
|
||||
if (error instanceof MxGatewayCommandException ex) {
|
||||
return new MxGatewayCommandException(message, scrub(ex.protocolStatus(), secret), ex.reply(), null);
|
||||
}
|
||||
if (error instanceof MxGatewaySessionException ex) {
|
||||
return new MxGatewaySessionException(message, scrub(ex.protocolStatus(), secret), null);
|
||||
}
|
||||
if (error instanceof MxGatewayWorkerException ex) {
|
||||
return new MxGatewayWorkerException(message, scrub(ex.protocolStatus(), secret), null);
|
||||
}
|
||||
if (error instanceof MxGatewayAuthenticationException) {
|
||||
return new MxGatewayAuthenticationException(message, null);
|
||||
}
|
||||
if (error instanceof MxGatewayAuthorizationException) {
|
||||
return new MxGatewayAuthorizationException(message, null);
|
||||
}
|
||||
return new MxGatewayException(message);
|
||||
}
|
||||
|
||||
private static ProtocolStatus scrub(ProtocolStatus status, String secret) {
|
||||
if (status == null) {
|
||||
return null;
|
||||
}
|
||||
return status.toBuilder()
|
||||
.setMessage(MxGatewaySecrets.redactExact(status.getMessage(), secret))
|
||||
.build();
|
||||
}
|
||||
|
||||
static void ensureProtocolSuccess(String operation, ProtocolStatus status, MxCommandReply reply) {
|
||||
if (status == null || status.getCode() == ProtocolStatusCode.PROTOCOL_STATUS_CODE_OK) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user