blob: bfe6868ac260acc68cf7e89a29f6dc4ab0c63a99 [file] [log] [blame]
/**
* 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.
*/
#include <algorithm>
#include <cctype>
#include "Exception.h"
#include "ExceptionInternal.h"
#include "SaslClient.h"
#define SASL_SUCCESS 0
namespace hdfs {
namespace internal {
SaslClient::SaslClient(const RpcSaslProto_SaslAuth & auth, const Token & token,
const std::string & principal) :
complete(false) {
int rc;
ctx = NULL;
RpcAuth method = RpcAuth(RpcAuth::ParseMethod(auth.method()));
rc = gsasl_init(&ctx);
if (rc != GSASL_OK) {
THROW(HdfsIOException, "cannot initialize libgsasl");
}
switch (method.getMethod()) {
case AuthMethod::KERBEROS:
initKerberos(auth, principal);
break;
case AuthMethod::TOKEN:
initDigestMd5(auth, token);
break;
default:
THROW(HdfsIOException, "unknown auth method.");
break;
}
}
SaslClient::~SaslClient() {
if (session != NULL) {
gsasl_finish(session);
}
if (ctx != NULL) {
gsasl_done(ctx);
}
}
void SaslClient::initKerberos(const RpcSaslProto_SaslAuth & auth,
const std::string & principal) {
int rc;
/* Create new authentication session. */
if ((rc = gsasl_client_start(ctx, auth.mechanism().c_str(), &session)) != GSASL_OK) {
THROW(HdfsIOException, "Cannot initialize client (%d): %s", rc,
gsasl_strerror(rc));
}
gsasl_property_set(session, GSASL_SERVICE, auth.protocol().c_str());
gsasl_property_set(session, GSASL_AUTHID, principal.c_str());
gsasl_property_set(session, GSASL_HOSTNAME, auth.serverid().c_str());
}
std::string Base64Encode(const std::string & in) {
char * temp;
size_t len;
std::string retval;
int rc = gsasl_base64_to(in.c_str(), in.size(), &temp, &len);
if (rc != GSASL_OK) {
throw std::bad_alloc();
}
if (temp) {
retval = temp;
free(temp);
}
if (!temp || retval.length() != len) {
THROW(HdfsIOException, "SaslClient: Failed to encode string to base64");
}
return retval;
}
void SaslClient::initDigestMd5(const RpcSaslProto_SaslAuth & auth,
const Token & token) {
int rc;
if ((rc = gsasl_client_start(ctx, auth.mechanism().c_str(), &session)) != GSASL_OK) {
THROW(HdfsIOException, "Cannot initialize client (%d): %s", rc, gsasl_strerror(rc));
}
std::string password = Base64Encode(token.getPassword());
std::string identifier = Base64Encode(token.getIdentifier());
gsasl_property_set(session, GSASL_PASSWORD, password.c_str());
gsasl_property_set(session, GSASL_AUTHID, identifier.c_str());
gsasl_property_set(session, GSASL_HOSTNAME, auth.serverid().c_str());
gsasl_property_set(session, GSASL_SERVICE, auth.protocol().c_str());
}
std::string SaslClient::evaluateChallenge(const std::string & challenge) {
int rc;
char * output = NULL;
size_t outputSize;
std::string retval;
rc = gsasl_step(session, &challenge[0], challenge.size(), &output,
&outputSize);
if (rc == GSASL_NEEDS_MORE || rc == GSASL_OK) {
retval.resize(outputSize);
memcpy(&retval[0], output, outputSize);
if (output) {
free(output);
}
} else {
if (output) {
free(output);
}
THROW(AccessControlException, "Failed to evaluate challenge: %s", gsasl_strerror(rc));
}
if (rc == GSASL_OK) {
complete = true;
}
return retval;
}
bool SaslClient::isComplete() {
return complete;
}
}
}