ClientDelegate.java
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() == && 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 !=&& 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 }