Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TSasl.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  *
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements. See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership. The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License") { you may not use this file except in compliance
10  * with the License. You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  ******************************************************************************/
21 #include "transport/config.h"
22 #ifdef HAVE_SASL_SASL_H
23 
24 #include <cstring>
25 #include <sstream>
26 #include <transport/TSasl.h>
27 #include <boost/algorithm/string.hpp>
28 
29 #include "common/logging.h"
30 
31 #include "common/names.h"
32 
33 DEFINE_bool(force_lowercase_usernames, false, "If true, all principals and usernames are"
34  " mapped to lowercase shortnames before being passed to any components (Sentry, "
35  "admission control) for authorization");
36 
37 using boost::algorithm::is_any_of;
38 using boost::algorithm::join;
39 using boost::algorithm::split;
40 using boost::algorithm::to_lower;
41 
42 namespace sasl {
43 
44 uint8_t* TSasl::unwrap(const uint8_t* incoming,
45  const int offset, const uint32_t len, uint32_t* outLen) {
46  uint32_t outputlen;
47  uint8_t* output;
48  int result;
49 
50  result = sasl_decode(conn,
51  (const char*)incoming, len, (const char**)&output, &outputlen);
52  if (result != SASL_OK) {
53  throw SaslException(sasl_errdetail(conn));
54  }
55  *outLen = outputlen;
56  return output;
57 }
58 
59 uint8_t* TSasl::wrap(const uint8_t* outgoing,
60  const int offset, const uint32_t len, uint32_t* outLen) {
61  uint32_t outputlen;
62  uint8_t* output;
63  int result;
64 
65  result = sasl_encode(conn, (const char*)outgoing+offset,
66  len, (const char**)&output, &outputlen);
67  if (result != SASL_OK) {
68  throw SaslException(sasl_errdetail(conn));
69  }
70  *outLen = outputlen;
71  return output;
72 }
73 
74 string TSasl::getUsername() {
75  const char* username;
76  int result =
77  sasl_getprop(conn, SASL_USERNAME, reinterpret_cast<const void **>(&username));
78  if (result != SASL_OK) {
79  stringstream ss;
80  ss << "Error getting SASL_USERNAME property: " << sasl_errstring(result, NULL, NULL);
81  throw SaslException(ss.str().c_str());
82  }
83  // Copy the username and return it to the caller. There is no cleanup/delete call for
84  // calls to sasl_getprops, the sasl layer handles the cleanup internally.
85  string ret(username);
86 
87  // Temporary fix to auth_to_local-style lowercase mapping from
88  // USER_NAME/REALM@DOMAIN.COM -> user_name/REALM@DOMAIN.COM
89  //
90  // TODO: The right fix is probably to use UserGroupInformation in the frontend which
91  // will use auth_to_local rules to do this.
92  if (FLAGS_force_lowercase_usernames) {
93  vector<string> components;
94  split(components, ret, is_any_of("@"));
95  if (components.size() > 0 ) {
96  to_lower(components[0]);
97  ret = join(components, "@");
98  }
99  }
100  return ret;
101 }
102 
103 TSaslClient::TSaslClient(const string& mechanisms, const string& authenticationId,
104  const string& protocol, const string& serverName, const map<string,string>& props,
105  sasl_callback_t* callbacks) {
106  conn = NULL;
107  if (!props.empty()) {
108  throw SaslServerImplException("Properties not yet supported");
109  }
110  int result = sasl_client_new(protocol.c_str(), serverName.c_str(),
111  NULL, NULL, callbacks, 0, &conn);
112  if (result != SASL_OK) {
113  if (conn) {
114  throw SaslServerImplException(sasl_errdetail(conn));
115  } else {
116  throw SaslServerImplException(sasl_errstring(result, NULL, NULL));
117  }
118  }
119 
120  if (!authenticationId.empty()) {
121  /* TODO: setup security property */
122  /*
123  sasl_security_properties_t secprops;
124  // populate secprops
125  result = sasl_setprop(conn, SASL_AUTH_EXTERNAL, authenticationId.c_str());
126  */
127  }
128 
129  chosenMech = mechList = mechanisms;
130  authComplete = false;
131  clientStarted = false;
132 }
133 
134 /* Evaluates the challenge data and generates a response. */
136  const uint8_t* challenge, const uint32_t len, uint32_t *resLen) {
137  sasl_interact_t* client_interact=NULL;
138  uint8_t* out=NULL;
139  uint32_t outlen=0;
140  uint32_t result;
141  char* mechUsing;
142 
143  if (!clientStarted) {
144  result=sasl_client_start(conn,
145  mechList.c_str(),
146  &client_interact, /* filled in if an interaction is needed */
147  (const char**)&out, /* filled in on success */
148  &outlen, /* filled in on success */
149  (const char**)&mechUsing);
150  clientStarted = true;
151  chosenMech = mechUsing;
152  } else {
153  if (len > 0) {
154  result=sasl_client_step(conn, /* our context */
155  (const char*)challenge, /* the data from the server */
156  len, /* its length */
157  &client_interact, /* this should be unallocated and NULL */
158  (const char**)&out, /* filled in on success */
159  &outlen); /* filled in on success */
160  } else {
161  result = SASL_CONTINUE;
162  }
163  }
164 
165  if (result == SASL_OK) {
166  authComplete = true;
167  } else if (result != SASL_CONTINUE) {
168  throw SaslClientImplException(sasl_errdetail(conn));
169  }
170  *resLen = outlen;
171  return (uint8_t*)out;
172 }
173 
174 /* Returns the IANA-registered mechanism name of this SASL client. */
176  return chosenMech;
177 }
178 
179 /* Retrieves the negotiated property */
180 string TSaslClient::getNegotiatedProperty(const string& propName) {
181  return NULL;
182 }
183 
184 /* Determines whether this mechanism has an optional initial response. */
186  // TODO: Need to return a value based on the mechanism.
187  return true;
188 }
189 
190 TSaslServer::TSaslServer(const string& service, const string& serverFQDN,
191  const string& userRealm,
192  unsigned flags, sasl_callback_t* callbacks) {
193  conn = NULL;
194  int result = sasl_server_new(service.c_str(),
195  serverFQDN.size() == 0 ? NULL : serverFQDN.c_str(),
196  userRealm.size() == 0 ? NULL :userRealm.c_str(),
197  NULL, NULL, callbacks, flags, &conn);
198  if (result != SASL_OK) {
199  if (conn) {
200  throw SaslServerImplException(sasl_errdetail(conn));
201  } else {
202  throw SaslServerImplException(sasl_errstring(result, NULL, NULL));
203  }
204  }
205 
206  authComplete = false;
207  serverStarted = false;
208 }
209 
210 uint8_t* TSaslServer::evaluateChallengeOrResponse(const uint8_t* response,
211  const uint32_t len, uint32_t* resLen) {
212  uint8_t* out = NULL;
213  uint32_t outlen = 0;
214  uint32_t result;
215 
216  if (!serverStarted) {
217  result = sasl_server_start(conn,
218  (const char *)response, NULL, 0, (const char **)&out, &outlen);
219  } else {
220  result = sasl_server_step(conn,
221  (const char*)response, len, (const char**)&out, &outlen);
222  }
223 
224  if (result == SASL_OK) {
225  authComplete = true;
226  } else if (result != SASL_CONTINUE) {
227  throw SaslServerImplException(sasl_errdetail(conn));
228  }
229  serverStarted = true;
230 
231  *resLen = outlen;
232  return out;
233 }
234 };
235 #endif
std::string getNegotiatedProperty(const std::string &propName)
sasl_conn_t * conn
Definition: TSasl.h:112
const StringSearch UrlParser::protocol_search & protocol
Definition: url-parser.cc:36
std::string chosenMech
Definition: TSasl.h:154
bool authComplete
Definition: TSasl.h:110
virtual std::string getMechanismName()
std::string getUsername()
DEFINE_bool(compact_catalog_topic, false,"If true, updates sent via the statestore are ""compacted before transmission. This saves network bandwidth at the cost of a small"" quantity of CPU time. Enable this option in cluster with large catalogs (make ""sure it is also enabled on receiving Impala demons as well).")
uint8_t * unwrap(const uint8_t *incoming, const int offset, const uint32_t len, uint32_t *outLen)
uint8_t * evaluateChallengeOrResponse(const uint8_t *challenge, const uint32_t len, uint32_t *outLen)
uint8_t * wrap(const uint8_t *outgoing, int offset, const uint32_t len, uint32_t *outLen)
virtual uint8_t * evaluateChallengeOrResponse(const uint8_t *challenge, const uint32_t len, uint32_t *resLen)
TSaslServer(const std::string &service, const std::string &serverFQDN, const std::string &userRealm, unsigned flags, sasl_callback_t *callbacks)
bool serverStarted
Definition: TSasl.h:188
uint8_t offset[7 *64-sizeof(uint64_t)]
std::string mechList
Definition: TSasl.h:157
virtual bool hasInitialResponse()
bool clientStarted
Definition: TSasl.h:151
TSaslClient(const std::string &mechanisms, const std::string &authorizationId, const std::string &protocol, const std::string &serverName, const std::map< std::string, std::string > &props, sasl_callback_t *callbacks)