use of io.pravega.auth.TokenException in project pravega by pravega.
the class AppendProcessor method handleException.
private Void handleException(UUID writerId, long requestId, String segment, long eventNumber, String doingWhat, Throwable u) {
if (u == null) {
IllegalStateException exception = new IllegalStateException("No exception to handle.");
log.error(requestId, "Append processor: Error {} on segment = '{}'", doingWhat, segment, exception);
throw exception;
}
u = Exceptions.unwrap(u);
String clientReplyStackTrace = replyWithStackTraceOnError ? Throwables.getStackTraceAsString(u) : EMPTY_STACK_TRACE;
if (u instanceof StreamSegmentExistsException) {
log.warn(requestId, "Segment '{}' already exists and {} cannot perform operation '{}'.", segment, writerId, doingWhat);
connection.send(new SegmentAlreadyExists(requestId, segment, clientReplyStackTrace));
} else if (u instanceof StreamSegmentNotExistsException) {
log.warn(requestId, "Segment '{}' does not exist and {} cannot perform operation '{}'.", segment, writerId, doingWhat);
connection.send(new NoSuchSegment(requestId, segment, clientReplyStackTrace, -1L));
} else if (u instanceof StreamSegmentSealedException) {
log.info("Segment '{}' is sealed and {} cannot perform operation '{}'.", segment, writerId, doingWhat);
connection.send(new SegmentIsSealed(requestId, segment, clientReplyStackTrace, eventNumber));
} else if (u instanceof ContainerNotFoundException) {
int containerId = ((ContainerNotFoundException) u).getContainerId();
log.warn(requestId, "Wrong host. Segment '{}' (Container {}) is not owned and {} cannot perform operation '{}'.", segment, containerId, writerId, doingWhat);
connection.send(new WrongHost(requestId, segment, "", clientReplyStackTrace));
} else if (u instanceof BadAttributeUpdateException) {
log.warn(requestId, "Bad attribute update by {} on segment {}.", writerId, segment, u);
connection.send(new InvalidEventNumber(writerId, requestId, clientReplyStackTrace));
close();
} else if (u instanceof TokenExpiredException) {
log.warn(requestId, "Token expired for writer {} on segment {}.", writerId, segment, u);
close();
} else if (u instanceof TokenException) {
log.warn(requestId, "Token check failed or writer {} on segment {}.", writerId, segment, u);
connection.send(new WireCommands.AuthTokenCheckFailed(requestId, clientReplyStackTrace, WireCommands.AuthTokenCheckFailed.ErrorCode.TOKEN_CHECK_FAILED));
} else if (u instanceof UnsupportedOperationException) {
log.warn(requestId, "Unsupported Operation '{}'.", doingWhat, u);
connection.send(new OperationUnsupported(requestId, doingWhat, clientReplyStackTrace));
} else if (u instanceof CancellationException) {
// Cancellation exception is thrown when the Operation processor is shutting down.
log.info("Closing connection '{}' while performing append on Segment '{}' due to {}.", connection, segment, u.toString());
close();
} else {
logError(segment, u);
// Closing connection should reinitialize things, and hopefully fix the problem
close();
}
return null;
}
use of io.pravega.auth.TokenException in project pravega by pravega.
the class PravegaRequestProcessor method handleException.
private Void handleException(long requestId, String segment, long offset, String operation, Throwable u) {
if (u == null) {
IllegalStateException exception = new IllegalStateException("No exception to handle.");
log.error(requestId, "Error (Segment = '{}', Operation = '{}')", segment, operation, exception);
throw exception;
}
u = Exceptions.unwrap(u);
String clientReplyStackTrace = replyWithStackTraceOnError ? Throwables.getStackTraceAsString(u) : EMPTY_STACK_TRACE;
final Consumer<Throwable> failureHandler = t -> {
log.error(requestId, "Error (Segment = '{}', Operation = '{}')", segment, "handling result of " + operation, t);
connection.close();
};
if (u instanceof StreamSegmentExistsException) {
log.info(requestId, "Segment '{}' already exists and cannot perform operation '{}'.", segment, operation);
invokeSafely(connection::send, new SegmentAlreadyExists(requestId, segment, clientReplyStackTrace), failureHandler);
} else if (u instanceof StreamSegmentNotExistsException) {
log.warn(requestId, "Segment '{}' does not exist and cannot perform operation '{}'.", segment, operation);
invokeSafely(connection::send, new NoSuchSegment(requestId, segment, clientReplyStackTrace, offset), failureHandler);
} else if (u instanceof StreamSegmentSealedException) {
log.info(requestId, "Segment '{}' is sealed and cannot perform operation '{}'.", segment, operation);
invokeSafely(connection::send, new SegmentIsSealed(requestId, segment, clientReplyStackTrace, offset), failureHandler);
} else if (u instanceof ContainerNotFoundException) {
int containerId = ((ContainerNotFoundException) u).getContainerId();
log.warn(requestId, "Wrong host. Segment = '{}' (Container {}) is not owned. Operation = '{}').", segment, containerId, operation);
invokeSafely(connection::send, new WrongHost(requestId, segment, "", clientReplyStackTrace), failureHandler);
} else if (u instanceof ReadCancellationException) {
log.info(requestId, "Sending empty response on connection {} while reading segment {} due to CancellationException.", connection, segment);
invokeSafely(connection::send, new SegmentRead(segment, offset, true, false, EMPTY_BUFFER, requestId), failureHandler);
} else if (u instanceof CancellationException) {
log.info(requestId, "Closing connection {} while performing {} due to {}.", connection, operation, u.toString());
connection.close();
} else if (u instanceof TokenExpiredException) {
log.warn(requestId, "Expired token during operation {}", operation);
invokeSafely(connection::send, new AuthTokenCheckFailed(requestId, clientReplyStackTrace, AuthTokenCheckFailed.ErrorCode.TOKEN_EXPIRED), failureHandler);
} else if (u instanceof TokenException) {
log.warn(requestId, "Token exception encountered during operation {}.", operation, u);
invokeSafely(connection::send, new AuthTokenCheckFailed(requestId, clientReplyStackTrace, AuthTokenCheckFailed.ErrorCode.TOKEN_CHECK_FAILED), failureHandler);
} else if (u instanceof UnsupportedOperationException) {
log.warn(requestId, "Unsupported Operation '{}'.", operation, u);
invokeSafely(connection::send, new OperationUnsupported(requestId, operation, clientReplyStackTrace), failureHandler);
} else if (u instanceof BadOffsetException) {
BadOffsetException badOffset = (BadOffsetException) u;
log.info(requestId, "Segment '{}' is truncated and cannot perform operation '{}' at offset '{}'", segment, operation, offset);
invokeSafely(connection::send, new SegmentIsTruncated(requestId, segment, badOffset.getExpectedOffset(), clientReplyStackTrace, offset), failureHandler);
} else if (u instanceof TableSegmentNotEmptyException) {
log.warn(requestId, "Table segment '{}' is not empty to perform '{}'.", segment, operation);
invokeSafely(connection::send, new TableSegmentNotEmpty(requestId, segment, clientReplyStackTrace), failureHandler);
} else if (u instanceof KeyNotExistsException) {
log.warn(requestId, "Conditional update on Table segment '{}' failed as the key does not exist.", segment);
invokeSafely(connection::send, new WireCommands.TableKeyDoesNotExist(requestId, segment, clientReplyStackTrace), failureHandler);
} else if (u instanceof BadKeyVersionException) {
log.warn(requestId, "Conditional update on Table segment '{}' failed due to bad key version.", segment);
invokeSafely(connection::send, new WireCommands.TableKeyBadVersion(requestId, segment, clientReplyStackTrace), failureHandler);
} else if (errorCodeExists(u)) {
log.warn(requestId, "Operation on segment '{}' failed due to a {}.", segment, u.getClass());
invokeSafely(connection::send, new WireCommands.ErrorMessage(requestId, segment, u.getMessage(), WireCommands.ErrorMessage.ErrorCode.valueOf(u.getClass())), failureHandler);
} else {
logError(requestId, segment, operation, u);
// Closing connection should reinitialize things, and hopefully fix the problem
connection.close();
throw new IllegalStateException("Unknown exception.", u);
}
return null;
}
use of io.pravega.auth.TokenException in project pravega by pravega.
the class TokenVerifierImpl method verifyToken.
@Override
public JsonWebToken verifyToken(@NonNull String resource, String token, @NonNull AuthHandler.Permissions expectedLevel) throws TokenExpiredException, InvalidTokenException, InvalidClaimException, TokenException {
if (Strings.isNullOrEmpty(token)) {
throw new InvalidTokenException("Token is null or empty");
}
// All key value pairs inside the payload are returned, including standard fields such as sub (for subject),
// aud (for audience), iat, exp, as well as custom fields of the form "<resource> -> <permission>" set by
// Pravega.
JsonWebToken jwt = JwtParser.parse(token, tokenSigningKey);
Map<String, Object> permissionsByResource = jwt.getPermissionsByResource();
Optional<Map.Entry<String, Object>> matchingClaim = permissionsByResource.entrySet().stream().filter(entry -> resourceMatchesClaimKey(entry.getKey(), resource) && expectedLevel.compareTo(AuthHandler.Permissions.valueOf(entry.getValue().toString())) <= 0).findFirst();
if (!matchingClaim.isPresent()) {
log.debug(String.format("No matching claim found for resource [%s] and permission [%s] in token.", resource, expectedLevel));
throw new InvalidClaimException(String.format("No matching claim found for resource: [%s] and permission: [%s] in the delegation token.", resource, expectedLevel));
}
return jwt;
}
use of io.pravega.auth.TokenException in project pravega by pravega.
the class AppendProcessor method setupAppend.
/**
* Setup an append so that subsequent append calls can occur.
* This requires validating that the segment exists.
* The reply: AppendSetup indicates that appends may proceed and contains the eventNumber which they should proceed
* from (in the event that this is a reconnect from a producer we have seen before)
*/
@Override
public void setupAppend(SetupAppend setupAppend) {
String newSegment = setupAppend.getSegment();
UUID writer = setupAppend.getWriterId();
log.info("Setting up appends for writer: {} on segment: {}", writer, newSegment);
if (this.tokenVerifier != null) {
try {
JsonWebToken token = tokenVerifier.verifyToken(newSegment, setupAppend.getDelegationToken(), AuthHandler.Permissions.READ_UPDATE);
setupTokenExpiryTask(setupAppend, token);
} catch (TokenException e) {
handleException(setupAppend.getWriterId(), setupAppend.getRequestId(), newSegment, "Update Segment Attribute", e);
return;
}
}
// Get the last Event Number for this writer from the Store. This operation (cache=true) will automatically put
// the value in the Store's cache so it's faster to access later.
AttributeId writerAttributeId = AttributeId.fromUUID(writer);
Futures.exceptionallyComposeExpecting(store.getAttributes(newSegment, Collections.singleton(writerAttributeId), true, TIMEOUT), e -> e instanceof StreamSegmentSealedException, () -> store.getAttributes(newSegment, Collections.singleton(writerAttributeId), false, TIMEOUT)).whenComplete((attributes, u) -> {
try {
if (u != null) {
handleException(writer, setupAppend.getRequestId(), newSegment, "setting up append", u);
} else {
// Last event number stored according to Segment store.
long eventNumber = attributes.getOrDefault(writerAttributeId, Attributes.NULL_ATTRIBUTE_VALUE);
// Create a new WriterState object based on the attribute value for the last event number for the writer.
// It should be noted that only one connection for a given segment writer is created by the client.
// The event number sent by the AppendSetup command is an implicit ack, the writer acks all events
// below the specified event number.
WriterState current = this.writerStates.put(Pair.of(newSegment, writer), new WriterState(eventNumber));
if (current != null) {
log.info("SetupAppend invoked again for writer {}. Last event number from store is {}. Prev writer state {}", writer, eventNumber, current);
}
connection.send(new AppendSetup(setupAppend.getRequestId(), newSegment, writer, eventNumber));
}
} catch (Throwable e) {
handleException(writer, setupAppend.getRequestId(), newSegment, "handling setupAppend result", e);
}
});
}
Aggregations