Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TSaslServerTransport.cpp
Go to the documentation of this file.
1 // This file will be removed when the code is accepted into the Thrift library.
2 /*
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements. See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership. The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License. You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied. See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  */
20 
21 #include "config.h"
22 #ifdef HAVE_SASL_SASL_H
23 #include <stdint.h>
24 #include <sstream>
25 #include <boost/shared_ptr.hpp>
26 #include <boost/scoped_ptr.hpp>
27 #include <boost/thread/locks.hpp>
28 #include <boost/thread/thread.hpp>
29 
30 #include <thrift/transport/TBufferTransports.h>
33 
34 #include "common/logging.h"
35 
36 #include "common/names.h"
37 
38 using namespace sasl;
39 
40 namespace apache { namespace thrift { namespace transport {
41 TSaslServerTransport::TSaslServerTransport(shared_ptr<TTransport> transport)
42  : TSaslTransport(transport) {
43 }
44 
45 TSaslServerTransport::TSaslServerTransport(const string& mechanism,
46  const string& protocol,
47  const string& serverName,
48  const string& realm,
49  unsigned flags,
50  const map<string, string>& props,
51  const vector<struct sasl_callback>& callbacks,
52  shared_ptr<TTransport> transport)
53  : TSaslTransport(transport) {
54  addServerDefinition(mechanism, protocol, serverName, realm, flags,
55  props, callbacks);
56 }
57 
59  const std::map<std::string, TSaslServerDefinition*>& serverMap,
60  boost::shared_ptr<TTransport> transport)
61  : TSaslTransport(transport) {
62  serverDefinitionMap_.insert(serverMap.begin(), serverMap.end());
63 }
64 
69  if (isClient_) {
70  throw TTransportException(
71  TTransportException::INTERNAL_ERROR, "Setting server in client transport");
72  }
73  sasl_.reset(saslServer);
74 }
75 
77  uint32_t resLength;
78  NegotiationStatus status;
79 
80  uint8_t* message = receiveSaslMessage(&status, &resLength);
81  // Message is a non-null terminated string; to use it like a
82  // C-string we have to copy it into a null-terminated buffer.
83  string message_str(reinterpret_cast<char*>(message), resLength);
84 
85  if (status != TSASL_START) {
86  stringstream ss;
87  ss << "Expecting START status, received " << status;
89  reinterpret_cast<const uint8_t*>(ss.str().c_str()), ss.str().size());
90  throw TTransportException(ss.str());
91  }
92  map<string, TSaslServerDefinition*>::iterator defn =
95  stringstream ss;
96  ss << "Unsupported mechanism type " << message_str;
98  reinterpret_cast<const uint8_t*>(ss.str().c_str()), ss.str().size());
99  throw TTransportException(TTransportException::BAD_ARGS, ss.str());
100  }
101 
102  TSaslServerDefinition* serverDefinition = defn->second;
103  sasl_.reset(new TSaslServer(serverDefinition->protocol_,
104  serverDefinition->serverName_,
105  serverDefinition->realm_,
106  serverDefinition->flags_,
107  &serverDefinition->callbacks_[0]));
108  // First argument is interpreted as C-string
109  sasl_->evaluateChallengeOrResponse(
110  reinterpret_cast<const uint8_t*>(message_str.c_str()), resLength, &resLength);
111 
112 }
113 
115  shared_ptr<TTransport> trans) {
116  lock_guard<mutex> l(transportMap_mutex_);
117  // Thrift servers use both an input and an output transport to communicate with
118  // clients. In principal, these can be different, but for SASL clients we require them
119  // to be the same so that the authentication state is identical for communication in
120  // both directions. In order to do this, we cache the transport that we return in a map
121  // keyed by the transport argument to this method. Then if there are two successive
122  // calls to getTransport() with the same transport, we are sure to return the same
123  // wrapped transport both times.
124  //
125  // However, the cache map would retain references to all the transports it ever
126  // created. Instead, we remove an entry in the map after it has been found for the first
127  // time, that is, after the second call to getTransport() with the same argument. That
128  // matches the calling pattern in TThreadedServer and TThreadPoolServer, which both call
129  // getTransport() twice in succession when a connection is established, and then never
130  // again. This is obviously brittle (what if for some reason getTransport() is called a
131  // third time?) but for our usage of Thrift it's a tolerable band-aid.
132  //
133  // An alternative approach is to use the 'custom deleter' feature of shared_ptr to
134  // ensure that when ret_transport is eventually deleted, its corresponding map entry is
135  // removed. That is likely to be error prone given the locking involved; for now we go
136  // with the simple solution.
137  map<shared_ptr<TTransport>, shared_ptr<TBufferedTransport> >::iterator trans_map =
138  transportMap_.find(trans);
139  VLOG_EVERY_N(2, 100) << "getTransport(): transportMap_ size is: "
140  << transportMap_.size();
141  shared_ptr<TBufferedTransport> ret_transport;
142  if (trans_map == transportMap_.end()) {
143  shared_ptr<TTransport> wrapped(new TSaslServerTransport(serverDefinitionMap_, trans));
144  ret_transport.reset(new TBufferedTransport(wrapped));
145  ret_transport.get()->open();
146  transportMap_[trans] = ret_transport;
147  } else {
148  ret_transport = trans_map->second;
149  transportMap_.erase(trans_map);
150  }
151  return ret_transport;
152 }
153 
154 }}}
155 #endif
std::map< boost::shared_ptr< TTransport >, boost::shared_ptr< TBufferedTransport > > transportMap_
const StringSearch UrlParser::protocol_search & protocol
Definition: url-parser.cc:36
void sendSaslMessage(const NegotiationStatus status, const uint8_t *payload, const uint32_t length, bool flush=true)
bool isClient_
True if this is a client.
std::map< std::string, TSaslServerDefinition * > serverDefinitionMap_
TSaslServerTransport(const std::map< std::string, TSaslServerDefinition * > &serverMap, boost::shared_ptr< TTransport > transport)
boost::shared_ptr< sasl::TSasl > sasl_
virtual boost::shared_ptr< TTransport > getTransport(boost::shared_ptr< TTransport > trans)
std::map< std::string, TSaslServerDefinition * > serverDefinitionMap_
uint8_t * receiveSaslMessage(NegotiationStatus *status, uint32_t *length)