| /** |
| * 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; |
| } |
| |
| } |
| } |
| |