blob: ba8f3e0f5631ef4ade398f3a17d7f212797e3ddd [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.james.imapserver.netty;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.SSLContext;
import org.apache.james.imap.api.ImapSessionState;
import org.apache.james.imap.api.process.ImapLineHandler;
import org.apache.james.imap.api.process.ImapSession;
import org.apache.james.imap.api.process.SelectedMailbox;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.handler.codec.compression.ZlibDecoder;
import org.jboss.netty.handler.codec.compression.ZlibEncoder;
import org.jboss.netty.handler.codec.compression.ZlibWrapper;
import org.jboss.netty.handler.ssl.SslHandler;
public class NettyImapSession implements ImapSession, NettyConstants {
private ImapSessionState state = ImapSessionState.NON_AUTHENTICATED;
private SelectedMailbox selectedMailbox;
private final Map<String, Object> attributesByKey = new HashMap<>();
private final SSLContext sslContext;
private final String[] enabledCipherSuites;
private final boolean compress;
private final Channel channel;
private int handlerCount;
private final boolean plainAuthDisallowed;
private final SessionId sessionId;
private boolean needsCommandInjectionDetection;
public NettyImapSession(Channel channel, SSLContext sslContext, String[] enabledCipherSuites, boolean compress, boolean plainAuthDisallowed, SessionId sessionId) {
this.channel = channel;
this.sslContext = sslContext;
this.enabledCipherSuites = enabledCipherSuites;
this.compress = compress;
this.plainAuthDisallowed = plainAuthDisallowed;
this.sessionId = sessionId;
this.needsCommandInjectionDetection = true;
}
@Override
public boolean needsCommandInjectionDetection() {
return needsCommandInjectionDetection;
}
@Override
public void startDetectingCommandInjection() {
needsCommandInjectionDetection = true;
}
@Override
public void stopDetectingCommandInjection() {
needsCommandInjectionDetection = false;
}
@Override
public SessionId sessionId() {
return sessionId;
}
@Override
public void logout() {
closeMailbox();
state = ImapSessionState.LOGOUT;
}
@Override
public void authenticated() {
this.state = ImapSessionState.AUTHENTICATED;
}
@Override
public void deselect() {
this.state = ImapSessionState.AUTHENTICATED;
closeMailbox();
}
@Override
public void selected(SelectedMailbox mailbox) {
this.state = ImapSessionState.SELECTED;
closeMailbox();
this.selectedMailbox = mailbox;
}
@Override
public SelectedMailbox getSelected() {
return this.selectedMailbox;
}
@Override
public ImapSessionState getState() {
return this.state;
}
private void closeMailbox() {
if (selectedMailbox != null) {
selectedMailbox.deselect();
selectedMailbox = null;
}
}
@Override
public Object getAttribute(String key) {
return attributesByKey.get(key);
}
@Override
public void setAttribute(String key, Object value) {
if (value == null) {
attributesByKey.remove(key);
} else {
attributesByKey.put(key, value);
}
}
@Override
public boolean startTLS() {
if (!supportStartTLS()) {
return false;
}
channel.setReadable(false);
SslHandler filter = new SslHandler(sslContext.createSSLEngine(), false);
filter.getEngine().setUseClientMode(false);
if (enabledCipherSuites != null && enabledCipherSuites.length > 0) {
filter.getEngine().setEnabledCipherSuites(enabledCipherSuites);
}
channel.getPipeline().addFirst(SSL_HANDLER, filter);
stopDetectingCommandInjection();
channel.setReadable(true);
return true;
}
@Override
public boolean supportStartTLS() {
return sslContext != null;
}
@Override
public boolean isCompressionSupported() {
return compress;
}
@Override
public boolean startCompression() {
if (!isCompressionSupported()) {
return false;
}
channel.setReadable(false);
ZlibDecoder decoder = new ZlibDecoder(ZlibWrapper.NONE);
ZlibEncoder encoder = new ZlibEncoder(ZlibWrapper.NONE, 5);
// Check if we have the SslHandler in the pipeline already
// if so we need to move the compress encoder and decoder
// behind it in the chain
// See JAMES-1186
if (channel.getPipeline().get(SSL_HANDLER) == null) {
channel.getPipeline().addFirst(ZLIB_DECODER, decoder);
channel.getPipeline().addFirst(ZLIB_ENCODER, encoder);
} else {
channel.getPipeline().addAfter(SSL_HANDLER, ZLIB_DECODER, decoder);
channel.getPipeline().addAfter(SSL_HANDLER, ZLIB_ENCODER, encoder);
}
channel.setReadable(true);
return true;
}
@Override
public void pushLineHandler(ImapLineHandler lineHandler) {
channel.setReadable(false);
channel.getPipeline().addBefore(REQUEST_DECODER, "lineHandler" + handlerCount++, new ImapLineHandlerAdapter(this, lineHandler));
channel.setReadable(true);
}
@Override
public void popLineHandler() {
channel.setReadable(false);
channel.getPipeline().remove("lineHandler" + --handlerCount);
channel.setReadable(true);
}
@Override
public boolean isPlainAuthDisallowed() {
return plainAuthDisallowed;
}
@Override
public boolean isTLSActive() {
return channel.getPipeline().get(SSL_HANDLER) != null;
}
@Override
public boolean supportMultipleNamespaces() {
return false;
}
@Override
public boolean isCompressionActive() {
return channel.getPipeline().get(ZLIB_DECODER) != null;
}
}