/*
* JBoss, Home of Professional Open Source
* Copyright 2010, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.remoting3;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.security.sasl.Sasl;
import org.wildfly.common.Assert;
import org.wildfly.security.auth.client.AuthenticationConfiguration;
import org.xnio.Option;
import org.xnio.OptionMap;
import org.xnio.Options;
import org.xnio.Property;
import org.xnio.Sequence;
import org.xnio.sasl.SaslQop;
import org.xnio.sasl.SaslStrength;
/**
* Common options for Remoting configuration.
*/
public final class RemotingOptions {
private static final String[] NO_STRINGS = new String[0];
private RemotingOptions() {
}
/**
* Merge the given option map into the given authentication configuration, and return the result.
*
* @param optionMap the option map (must not be {@code null})
* @param authenticationConfiguration the authentication configuration (must not be {@code null})
* @return the merged authentication configuration (not {@code null})
*/
public static AuthenticationConfiguration mergeOptionsIntoAuthenticationConfiguration(OptionMap optionMap, AuthenticationConfiguration authenticationConfiguration) {
Assert.checkNotNullParam("optionMap", optionMap);
Assert.checkNotNullParam("authenticationConfiguration", authenticationConfiguration);
final String protocol = optionMap.get(SASL_PROTOCOL);
if (protocol != null) {
authenticationConfiguration = authenticationConfiguration.useProtocol(protocol);
}
final String realm = optionMap.get(AUTH_REALM);
if (realm != null) {
authenticationConfiguration = authenticationConfiguration.useRealm(realm);
}
final String authzId = optionMap.get(AUTHORIZE_ID);
if (authzId != null) {
authenticationConfiguration = authenticationConfiguration.useAuthorizationName(authzId);
}
final Sequence<String> disallowedMechs = optionMap.get(Options.SASL_DISALLOWED_MECHANISMS);
if (disallowedMechs != null) {
authenticationConfiguration = authenticationConfiguration.forbidSaslMechanisms(disallowedMechs.toArray(NO_STRINGS));
}
final Sequence<String> mechanisms = optionMap.get(Options.SASL_MECHANISMS);
if (mechanisms != null) {
authenticationConfiguration = authenticationConfiguration.allowSaslMechanisms(mechanisms.toArray(NO_STRINGS));
}
final Map<String, String> saslPropertiesMap = new HashMap<>();
final Sequence<Property> properties = optionMap.get(Options.SASL_PROPERTIES);
if (properties != null) {
for (Property property : properties) {
// ELY-894
//noinspection rawtypes,unchecked
((Map)saslPropertiesMap).put(property.getKey(), property.getValue());
}
}
final Boolean forwardSecrecy = optionMap.get(Options.SASL_POLICY_FORWARD_SECRECY);
if (forwardSecrecy != null) {
saslPropertiesMap.put(Sasl.POLICY_FORWARD_SECRECY, forwardSecrecy.toString());
}
final Boolean noActive = optionMap.get(Options.SASL_POLICY_NOACTIVE);
if (noActive != null) {
saslPropertiesMap.put(Sasl.POLICY_NOACTIVE, noActive.toString());
}
final Boolean noAnonymous = optionMap.get(Options.SASL_POLICY_NOANONYMOUS);
if (noAnonymous != null) {
saslPropertiesMap.put(Sasl.POLICY_NOANONYMOUS, noAnonymous.toString());
}
final Boolean noDictionary = optionMap.get(Options.SASL_POLICY_NODICTIONARY);
if (noDictionary != null) {
saslPropertiesMap.put(Sasl.POLICY_NODICTIONARY, noDictionary.toString());
}
final Boolean noPlainText = optionMap.get(Options.SASL_POLICY_NOPLAINTEXT);
if (noPlainText != null) {
saslPropertiesMap.put(Sasl.POLICY_NOPLAINTEXT, noPlainText.toString());
}
final Boolean passCredentials = optionMap.get(Options.SASL_POLICY_PASS_CREDENTIALS);
if (passCredentials != null) {
saslPropertiesMap.put(Sasl.POLICY_PASS_CREDENTIALS, passCredentials.toString());
}
final Sequence<SaslQop> qop = optionMap.get(Options.SASL_QOP);
if (qop != null) {
final Iterator<SaslQop> iterator = qop.iterator();
if (iterator.hasNext()) {
StringBuilder b = new StringBuilder().append(iterator.next().getString());
while (iterator.hasNext()) {
b.append(',').append(iterator.next().getString());
}
saslPropertiesMap.put(Sasl.QOP, b.toString());
}
}
final Boolean reuse = optionMap.get(Options.SASL_REUSE);
if (reuse != null) {
saslPropertiesMap.put(Sasl.REUSE, reuse.toString());
}
final SaslStrength strength = optionMap.get(Options.SASL_STRENGTH);
if (strength != null) {
switch (strength) {
case LOW: saslPropertiesMap.put(Sasl.STRENGTH, "low"); break;
case MEDIUM: saslPropertiesMap.put(Sasl.STRENGTH, "medium"); break;
case HIGH: saslPropertiesMap.put(Sasl.STRENGTH, "high"); break;
default: throw Assert.impossibleSwitchCase(strength);
}
}
final Boolean serverAuth = optionMap.get(Options.SASL_SERVER_AUTH);
if (serverAuth != null) {
saslPropertiesMap.put(Sasl.SERVER_AUTH, serverAuth.toString());
}
if (! saslPropertiesMap.isEmpty()) {
authenticationConfiguration = authenticationConfiguration.useMechanismProperties(saslPropertiesMap);
}
return authenticationConfiguration;
}
/**
* The size of the largest buffer that this endpoint will transmit over a connection.
*/
public static final Option<Integer> SEND_BUFFER_SIZE = Option.simple(RemotingOptions.class, "SEND_BUFFER_SIZE", Integer.class);
/**
* The default send buffer size.
*/
public static final int DEFAULT_SEND_BUFFER_SIZE = 8192;
/**
* The size of the largest buffer that this endpoint will accept over a connection.
*/
public static final Option<Integer> RECEIVE_BUFFER_SIZE = Option.simple(RemotingOptions.class, "RECEIVE_BUFFER_SIZE", Integer.class);
/**
* The default receive buffer size.
*/
public static final int DEFAULT_RECEIVE_BUFFER_SIZE = 8192;
/**
* The size of allocated buffer regions.
*/
public static final Option<Integer> BUFFER_REGION_SIZE = Option.simple(RemotingOptions.class, "BUFFER_REGION_SIZE", Integer.class);
/**
* The maximum window size of the transmit direction for connection channels, in bytes.
*/
public static final Option<Integer> TRANSMIT_WINDOW_SIZE = Option.simple(RemotingOptions.class, "TRANSMIT_WINDOW_SIZE", Integer.class);
/**
* The default requested window size of the transmit direction for incoming channel open attempts.
*/
public static final int INCOMING_CHANNEL_DEFAULT_TRANSMIT_WINDOW_SIZE = 0x20000;
/**
* The default requested window size of the transmit direction for outgoing channel open attempts.
*/
public static final int OUTGOING_CHANNEL_DEFAULT_TRANSMIT_WINDOW_SIZE = Integer.MAX_VALUE;
/**
* The maximum window size of the receive direction for connection channels, in bytes.
*/
public static final Option<Integer> RECEIVE_WINDOW_SIZE = Option.simple(RemotingOptions.class, "RECEIVE_WINDOW_SIZE", Integer.class);
/**
* The default requested window size of the receive direction for incoming channel open attempts.
*/
public static final int INCOMING_CHANNEL_DEFAULT_RECEIVE_WINDOW_SIZE = 0x20000;
/**
* The default requested window size of the receive direction for outgoing channel open attempts.
*/
public static final int OUTGOING_CHANNEL_DEFAULT_RECEIVE_WINDOW_SIZE = 0x20000;
/**
* The maximum number of outbound channels to support for a connection.
*/
public static final Option<Integer> MAX_OUTBOUND_CHANNELS = Option.simple(RemotingOptions.class, "MAX_OUTBOUND_CHANNELS", Integer.class);
/**
* The default maximum number of outbound channels.
*/
public static final int DEFAULT_MAX_OUTBOUND_CHANNELS = 40;
/**
* The maximum number of inbound channels to support for a connection.
*/
public static final Option<Integer> MAX_INBOUND_CHANNELS = Option.simple(RemotingOptions.class, "MAX_INBOUND_CHANNELS", Integer.class);
/**
* The default maximum number of inbound channels.
*/
public static final int DEFAULT_MAX_INBOUND_CHANNELS = 40;
/**
* The SASL authorization ID. Used as authentication user name to use if no authentication {@code CallbackHandler} is specified
* and the selected SASL mechanism demands a user name.
*/
public static final Option<String> AUTHORIZE_ID = Option.simple(RemotingOptions.class, "AUTHORIZE_ID", String.class);
/**
* Deprecated alias for {@link #AUTHORIZE_ID}.
*/
@Deprecated
public static final Option<String> AUTH_USER_NAME = AUTHORIZE_ID;
/**
* The authentication realm to use if no authentication {@code CallbackHandler} is specified.
*/
public static final Option<String> AUTH_REALM = Option.simple(RemotingOptions.class, "AUTH_REALM", String.class);
/**
* Specify the number of times a client is allowed to retry authentication before closing the connection.
*/
public static final Option<Integer> AUTHENTICATION_RETRIES = Option.simple(RemotingOptions.class, "AUTHENTICATION_RETRIES", Integer.class);
/**
* The default number of authentication retries.
*/
public static final int DEFAULT_AUTHENTICATION_RETRIES = 3;
/**
* The maximum number of concurrent outbound messages on a channel.
*/
public static final Option<Integer> MAX_OUTBOUND_MESSAGES = Option.simple(RemotingOptions.class, "MAX_OUTBOUND_MESSAGES", Integer.class);
/**
* The default maximum number of concurrent outbound messages on an incoming channel.
*/
public static final int INCOMING_CHANNEL_DEFAULT_MAX_OUTBOUND_MESSAGES = 80;
/**
* The default maximum number of concurrent outbound messages on an outgoing channel.
*/
public static final int OUTGOING_CHANNEL_DEFAULT_MAX_OUTBOUND_MESSAGES = 0xffff;
/**
* The maximum number of concurrent inbound messages on a channel.
*/
public static final Option<Integer> MAX_INBOUND_MESSAGES = Option.simple(RemotingOptions.class, "MAX_INBOUND_MESSAGES", Integer.class);
/**
* The default maximum number of concurrent inbound messages on a channel.
*/
public static final int DEFAULT_MAX_INBOUND_MESSAGES = 80;
/**
* The interval to use for connection heartbeat, in milliseconds. If the connection is idle in the outbound direction
* for this amount of time, a ping message will be sent, which will trigger a corresponding reply message.
*/
public static final Option<Integer> HEARTBEAT_INTERVAL = Option.simple(RemotingOptions.class, "HEARTBEAT_INTERVAL", Integer.class);
/**
* The default heartbeat interval.
*/
public static final int DEFAULT_HEARTBEAT_INTERVAL = Integer.MAX_VALUE;
/**
* The maximum inbound message size to be allowed. Messages exceeding this size will cause an exception to be thrown
* on the reading side as well as the writing side.
*/
public static final Option<Long> MAX_INBOUND_MESSAGE_SIZE = Option.simple(RemotingOptions.class, "MAX_INBOUND_MESSAGE_SIZE", Long.class);
/**
* The default maximum inbound message size.
*/
public static final long DEFAULT_MAX_INBOUND_MESSAGE_SIZE = Long.MAX_VALUE;
/**
* The maximum outbound message size to send. No messages larger than this well be transmitted; attempting to do
* so will cause an exception on the writing side.
*/
public static final Option<Long> MAX_OUTBOUND_MESSAGE_SIZE = Option.simple(RemotingOptions.class, "MAX_OUTBOUND_MESSAGE_SIZE", Long.class);
/**
* The default maximum outbound message size.
*/
public static final long DEFAULT_MAX_OUTBOUND_MESSAGE_SIZE = Long.MAX_VALUE;
/**
* The server side of the connection passes it's name to the client in the initial greeting, by default the name is
* automatically discovered from the local address of the connection or it can be overridden using this {@code Option}.
*/
public static final Option<String> SERVER_NAME = Option.simple(RemotingOptions.class, "SERVER_NAME", String.class);
/**
* Where a {@code SaslServer} or {@code SaslClient} are created by default the protocol specified it 'remoting', this
* {@code Option} can be used to override this.
*/
public static final Option<String> SASL_PROTOCOL = Option.simple(RemotingOptions.class, "SASL_PROTOCOL", String.class);
/**
* The default SASL protocol name.
*/
public static final String DEFAULT_SASL_PROTOCOL = "remote";
}