001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.transport;
022
023 import static org.apache.qpid.transport.Connection.State.OPEN;
024
025 import java.util.HashMap;
026 import java.util.List;
027 import java.util.Map;
028
029 import javax.security.sasl.Sasl;
030 import javax.security.sasl.SaslClient;
031 import javax.security.sasl.SaslException;
032
033 import org.apache.qpid.security.UsernamePasswordCallbackHandler;
034 import org.apache.qpid.transport.util.Logger;
035
036
037 /**
038 * ClientDelegate
039 *
040 */
041
042 public class ClientDelegate extends ConnectionDelegate
043 {
044 private static final Logger log = Logger.get(ClientDelegate.class);
045
046 private String vhost;
047 private String username;
048 private String password;
049 private String[] saslMechs;
050 private String protocol;
051 private String serverName;
052
053 public ClientDelegate(String vhost, String username, String password,String saslMechs)
054 {
055 this.vhost = vhost;
056 this.username = username;
057 this.password = password;
058 this.saslMechs = saslMechs.split(" ");
059
060 // Looks kinda of silly but the Sun SASL Kerberos client uses the
061 // protocol + servername as the service key.
062 this.protocol = System.getProperty("qpid.sasl_protocol","AMQP");
063 this.serverName = System.getProperty("qpid.sasl_server_name","localhost");
064 }
065
066 public void init(Connection conn, ProtocolHeader hdr)
067 {
068 if (!(hdr.getMajor() == 0 && hdr.getMinor() == 10))
069 {
070 conn.exception(new ProtocolVersionException(hdr.getMajor(), hdr.getMinor()));
071 }
072 }
073
074 @Override public void connectionStart(Connection conn, ConnectionStart start)
075 {
076 Map clientProperties = new HashMap();
077 clientProperties.put("qpid.session_flow", 1);
078
079 List<Object> mechanisms = start.getMechanisms();
080 if (mechanisms == null || mechanisms.isEmpty())
081 {
082 conn.connectionStartOk
083 (clientProperties, null, null, conn.getLocale());
084 return;
085 }
086
087 String[] mechs = new String[mechanisms.size()];
088 mechanisms.toArray(mechs);
089
090 try
091 {
092 UsernamePasswordCallbackHandler handler =
093 new UsernamePasswordCallbackHandler();
094 handler.initialise(username, password);
095 SaslClient sc = Sasl.createSaslClient
096 (saslMechs, null, protocol, serverName, null, handler);
097 conn.setSaslClient(sc);
098
099 byte[] response = sc.hasInitialResponse() ?
100 sc.evaluateChallenge(new byte[0]) : null;
101 conn.connectionStartOk
102 (clientProperties, sc.getMechanismName(), response,
103 conn.getLocale());
104 }
105 catch (SaslException e)
106 {
107 conn.exception(e);
108 }
109 }
110
111 @Override public void connectionSecure(Connection conn, ConnectionSecure secure)
112 {
113 SaslClient sc = conn.getSaslClient();
114 try
115 {
116 byte[] response = sc.evaluateChallenge(secure.getChallenge());
117 conn.connectionSecureOk(response);
118 }
119 catch (SaslException e)
120 {
121 conn.exception(e);
122 }
123 }
124
125 @Override public void connectionTune(Connection conn, ConnectionTune tune)
126 {
127 conn.setChannelMax(tune.getChannelMax());
128 int hb_interval = calculateHeartbeatInterval(conn,
129 tune.getHeartbeatMin(),
130 tune.getHeartbeatMax()
131 );
132 conn.connectionTuneOk(tune.getChannelMax(),
133 tune.getMaxFrameSize(),
134 hb_interval);
135 conn.setIdleTimeout(hb_interval*1000);
136 conn.connectionOpen(vhost, null, Option.INSIST);
137 }
138
139 @Override public void connectionOpenOk(Connection conn, ConnectionOpenOk ok)
140 {
141 conn.setState(OPEN);
142 }
143
144 @Override public void connectionRedirect(Connection conn, ConnectionRedirect redir)
145 {
146 throw new UnsupportedOperationException();
147 }
148
149 /**
150 * Currently the spec specified the min and max for heartbeat using secs
151 */
152 private int calculateHeartbeatInterval(Connection conn,int min, int max)
153 {
154 long l = conn.getIdleTimeout()/1000;
155 if (l !=0 && l >= min && l <= max)
156 {
157 return (int)l;
158 }
159 else
160 {
161 log.warn("Ignoring the idle timeout %s set by the connection," +
162 " using the brokers max value %s", l,max);
163 return max;
164 }
165 }
166 }
|