blob: d4671bb8109777e1e9ac4a90a8d95fc35babd4f5 [file] [log] [blame]
// This file will be removed when the code is accepted into the Thrift library.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef IMPALA_TRANSPORT_TSASL_H
#define IMPALA_TRANSPORT_TSASL_H
#include <string>
#include <map>
#include <stdint.h>
#include <stdexcept>
#ifdef _WIN32
#include <sasl.h>
#include <saslplug.h>
#include <saslutil.h>
#else /* _WIN32 */
#include <sasl/sasl.h>
#include <sasl/saslplug.h>
#include <sasl/saslutil.h>
#endif
#include <thrift/transport/TTransportException.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wheader-hygiene"
using namespace apache::thrift::transport;
#pragma clang diagnostic pop
namespace sasl {
class SaslException : public TTransportException {
public:
SaslException(const char* msg) : TTransportException(msg) {
}
};
/**
* These classes implement the Simple Authentication and Security Layer (SASL)
* authentication mechanisms. see: http://www.ietf.org/rfc/rfc2222.txt.
* They are mostly wrappers for the cyrus-sasl library routines.
*/
class TSasl {
public:
/* Setup the SASL negotiation state. */
virtual void setupSaslContext() = 0;
/* Reset the SASL negotiation state. */
virtual void resetSaslContext() = 0;
virtual ~TSasl() { disposeSaslContext(); }
/*
* Called once per application to free resources.`
* Note that there is no distinction in the sasl library between being done
* with servers or done with clients. Internally the library maintains a which
* is being used. A call to SaslDone should only happen after all clients
* and servers are finished.
*/
static void SaslDone() {
sasl_done();
}
/* Evaluates the challenge or response data and generates a response. */
virtual uint8_t* evaluateChallengeOrResponse(const uint8_t* challenge,
uint32_t len, uint32_t* resLen) = 0;
/* Determines whether the authentication exchange has completed. */
bool isComplete() {
return authComplete;
}
/*
* Unwraps a received byte array.
* Returns a buffer for unwrapped result, and sets
* 'len' to the buffer's length. The buffer is only valid until the next call, or
* until the client is closed.
*/
uint8_t* unwrap(const uint8_t* incoming, const int offset,
const uint32_t len, uint32_t* outLen);
/*
* Wraps a byte array to be sent.
* Returns a buffer of wrapped result, and sets
* 'len' to the buffer's length. The buffer is only valid until the next call, or
* until the client is closed.
*/
uint8_t* wrap(const uint8_t* outgoing, int offset,
const uint32_t len, uint32_t* outLen);
/* Returns the IANA-registered mechanism name. */
virtual std::string getMechanismName() { return NULL; }
/* Determines whether this mechanism has an optional initial response. */
virtual bool hasInitialResponse() { return false; }
/* Returns the username from the underlying sasl connection. */
std::string getUsername();
protected:
/* Name of service */
std::string service;
/* FQDN of server in use or the server to connect to */
std::string serverFQDN;
/* Authorization is complete. */
bool authComplete;
/*
* Callbacks to provide to the Cyrus-SASL library. Not owned. The user of the class
* must ensure that the callbacks live as long as the TSasl instance in use.
*/
sasl_callback_t* callbacks;
/* Sasl Connection. */
sasl_conn_t* conn;
TSasl(const std::string& service, const std::string& serverFQDN,
sasl_callback_t* callbacks);
/* Dispose of the SASL state. It is called once per connection as a part of teardown. */
void disposeSaslContext() {
if (conn != nullptr) {
sasl_dispose(&conn);
conn = NULL;
}
}
};
class SaslClientImplException : public SaslException {
public:
SaslClientImplException(const char* errMsg)
: SaslException(errMsg) {
}
};
/* Client sasl implementation class. */
class TSaslClient : public sasl::TSasl {
public:
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);
static void SaslInit(sasl_callback_t* callbacks) {
int result = sasl_client_init(callbacks);
if (result != SASL_OK)
throw SaslClientImplException(sasl_errstring(result, NULL, NULL));
}
/* Evaluates the challenge data and generates a response. */
uint8_t* evaluateChallengeOrResponse(const uint8_t* challenge,
const uint32_t len, uint32_t* outLen);
/* Returns the IANA-registered mechanism name of this SASL client. */
virtual std::string getMechanismName();
/* Retrieves the negotiated property */
std::string getNegotiatedProperty(const std::string& propName);
/* Setup the SASL client negotiation state. */
virtual void setupSaslContext();
/* Reset the SASL client negotiation state. */
virtual void resetSaslContext();
/* Determines whether this mechanism has an optional initial response. */
virtual bool hasInitialResponse();
private :
/* true if sasl_client_start has been called. */
bool clientStarted;
/* The chosen mechanism. */
std::string chosenMech;
/* List of possible mechanisms. */
std::string mechList;
};
class SaslServerImplException : public SaslException {
public:
SaslServerImplException(const char* errMsg)
: SaslException(errMsg) {
}
};
/* Server sasl implementation class. */
class TSaslServer : public sasl::TSasl {
public:
TSaslServer(const std::string& service, const std::string& serverFQDN,
const std::string& userRealm, unsigned flags, sasl_callback_t* callbacks);
/*
* This initializes the sasl server library and should be called onece per application.
* Note that the caller needs to ensure the life time of 'callbacks' and 'appname' is
* beyond that of this object.
*/
static void SaslInit(const sasl_callback_t* callbacks, const char* appname) {
int result = sasl_server_init(callbacks, appname);
if (result != SASL_OK) {
throw SaslServerImplException(sasl_errstring(result, NULL, NULL));
}
}
/* Setup the SASL server negotiation state. */
virtual void setupSaslContext();
/* Reset the SASL server negotiation state. */
virtual void resetSaslContext();
/* Evaluates the response data and generates a challenge. */
virtual uint8_t* evaluateChallengeOrResponse(const uint8_t* challenge,
const uint32_t len, uint32_t* resLen);
private:
/* The domain of the user agent */
std::string userRealm;
/* Flags to pass down to the SASL library */
unsigned flags;
/* true if sasl_server_start has been called. */
bool serverStarted;
};
}
#endif /* IMPALA_TRANSPORT_TSASL_H */