blob: 0f50d04fdb85cbc8f9ef49a9f25ba13f80ac8387 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.qpid.protonj2.engine.impl.sasl;
import org.apache.qpid.protonj2.engine.EngineHandler;
import org.apache.qpid.protonj2.engine.EngineHandlerContext;
import org.apache.qpid.protonj2.engine.EngineState;
import org.apache.qpid.protonj2.engine.HeaderEnvelope;
import org.apache.qpid.protonj2.engine.IncomingAMQPEnvelope;
import org.apache.qpid.protonj2.engine.OutgoingAMQPEnvelope;
import org.apache.qpid.protonj2.engine.SASLEnvelope;
import org.apache.qpid.protonj2.engine.exceptions.ProtocolViolationException;
import org.apache.qpid.protonj2.engine.impl.ProtonEngine;
import org.apache.qpid.protonj2.engine.impl.ProtonEngineNoOpSaslDriver;
/**
* Base class used for common portions of the SASL processing pipeline.
*/
public final class ProtonSaslHandler implements EngineHandler {
private EngineHandlerContext context;
private ProtonEngineSaslDriver driver;
private ProtonEngine engine;
private ProtonSaslContext saslContext;
/**
* @return true if the SASL exchange has finished (succeed or failed).
*/
public boolean isDone() {
return saslContext != null ? saslContext.isDone() : false;
}
@Override
public void handlerAdded(EngineHandlerContext context) {
this.engine = (ProtonEngine) context.engine();
this.driver = new ProtonEngineSaslDriver(engine, this);
this.context = context;
engine.registerSaslDriver(driver);
}
@Override
public void handlerRemoved(EngineHandlerContext context) {
this.driver = null;
this.saslContext = null;
this.engine = null;
this.context = null;
// If the engine wasn't started then it is okay to remove this handler otherwise
// we would only be removed from the pipeline on completion of SASL negotiations
// and the driver must remain to convey the outcome.
if (context.engine().state() == EngineState.IDLE) {
((ProtonEngine) context.engine()).registerSaslDriver(ProtonEngineNoOpSaslDriver.INSTANCE);
}
}
@Override
public void engineStarting(EngineHandlerContext context) {
driver.handleEngineStarting(engine);
}
@Override
public void handleRead(EngineHandlerContext context, HeaderEnvelope header) {
if (isDone()) {
context.fireRead(header);
} else {
// Default to server if application has not configured one way or the other.
saslContext = driver.context();
if (saslContext == null) {
saslContext = driver.server();
}
header.invoke(saslContext.headerReadContext(), context);
}
}
@Override
public void handleRead(EngineHandlerContext context, SASLEnvelope frame) {
if (isDone()) {
throw new ProtocolViolationException("Unexpected SASL Frame: SASL processing has already completed");
} else {
frame.invoke(safeGetSaslContext().saslReadContext(), context);
}
}
@Override
public void handleRead(EngineHandlerContext context, IncomingAMQPEnvelope frame) {
if (isDone()) {
context.fireRead(frame);
} else {
throw new ProtocolViolationException("Unexpected AMQP Frame: SASL processing not yet completed");
}
}
@Override
public void handleWrite(EngineHandlerContext context, HeaderEnvelope frame) {
if (isDone()) {
context.fireWrite(frame);
} else {
// Default to client if application has not configured one way or the other.
saslContext = driver.context();
if (saslContext == null) {
saslContext = driver.client();
}
// Delegate write to the SASL Context in use to allow for state updates.
frame.invoke(saslContext.headerWriteContext(), context);
}
}
@Override
public void handleWrite(EngineHandlerContext context, OutgoingAMQPEnvelope frame) {
if (isDone()) {
context.fireWrite(frame);
} else {
throw new ProtocolViolationException("Unexpected AMQP Performative: SASL processing not yet completed");
}
}
@Override
public void handleWrite(EngineHandlerContext context, SASLEnvelope frame) {
if (isDone()) {
throw new ProtocolViolationException("Unexpected SASL Performative: SASL processing has yet completed");
} else {
// Delegate to the SASL Context to allow state tracking to be maintained.
frame.invoke(safeGetSaslContext().saslWriteContext(), context);
}
}
//----- Internal implementation API and helper methods
ProtonEngine engine() {
return engine;
}
EngineHandlerContext context() {
return context;
}
private ProtonSaslContext safeGetSaslContext() {
if (saslContext != null) {
return saslContext;
}
throw new IllegalStateException("Cannot process incoming SASL performative, driver not yet initialized");
}
}