1/********************************************************************
2 * Copyright (c) 2013 - 2014, Pivotal Inc.
3 * All rights reserved.
4 *
5 * Author: Zhanwei Wang
6 ********************************************************************/
7/********************************************************************
8 * 2014 -
9 * open source under Apache License Version 2.0
10 ********************************************************************/
11/**
12 * Licensed to the Apache Software Foundation (ASF) under one
13 * or more contributor license agreements. See the NOTICE file
14 * distributed with this work for additional information
15 * regarding copyright ownership. The ASF licenses this file
16 * to you under the Apache License, Version 2.0 (the
17 * "License"); you may not use this file except in compliance
18 * with the License. You may obtain a copy of the License at
19 *
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28#include <algorithm>
29#include <cctype>
30
31#include "Exception.h"
32#include "ExceptionInternal.h"
33#include "SaslClient.h"
34
35#define SASL_SUCCESS 0
36
37namespace Hdfs {
38namespace Internal {
39
40SaslClient::SaslClient(const RpcSaslProto_SaslAuth & auth, const Token & token,
41 const std::string & principal) :
42 complete(false) {
43 int rc;
44 ctx = NULL;
45 RpcAuth method = RpcAuth(RpcAuth::ParseMethod(auth.method()));
46 rc = gsasl_init(&ctx);
47
48 if (rc != GSASL_OK) {
49 THROW(HdfsIOException, "cannot initialize libgsasl");
50 }
51
52 switch (method.getMethod()) {
53 case AuthMethod::KERBEROS:
54 initKerberos(auth, principal);
55 break;
56
57 case AuthMethod::TOKEN:
58 initDigestMd5(auth, token);
59 break;
60
61 default:
62 THROW(HdfsIOException, "unknown auth method.");
63 break;
64 }
65}
66
67SaslClient::~SaslClient() {
68 if (session != NULL) {
69 gsasl_finish(session);
70 }
71
72 if (ctx != NULL) {
73 gsasl_done(ctx);
74 }
75}
76
77void SaslClient::initKerberos(const RpcSaslProto_SaslAuth & auth,
78 const std::string & principal) {
79 int rc;
80
81 /* Create new authentication session. */
82 if ((rc = gsasl_client_start(ctx, auth.mechanism().c_str(), &session)) != GSASL_OK) {
83 THROW(HdfsIOException, "Cannot initialize client (%d): %s", rc,
84 gsasl_strerror(rc));
85 }
86
87 gsasl_property_set(session, GSASL_SERVICE, auth.protocol().c_str());
88 gsasl_property_set(session, GSASL_AUTHID, principal.c_str());
89 gsasl_property_set(session, GSASL_HOSTNAME, auth.serverid().c_str());
90}
91
92std::string Base64Encode(const std::string & in) {
93 char * temp;
94 size_t len;
95 std::string retval;
96 int rc = gsasl_base64_to(in.c_str(), in.size(), &temp, &len);
97
98 if (rc != GSASL_OK) {
99 throw std::bad_alloc();
100 }
101
102 if (temp) {
103 retval = temp;
104 free(temp);
105 }
106
107 if (!temp || retval.length() != len) {
108 THROW(HdfsIOException, "SaslClient: Failed to encode string to base64");
109 }
110
111 return retval;
112}
113
114void SaslClient::initDigestMd5(const RpcSaslProto_SaslAuth & auth,
115 const Token & token) {
116 int rc;
117
118 if ((rc = gsasl_client_start(ctx, auth.mechanism().c_str(), &session)) != GSASL_OK) {
119 THROW(HdfsIOException, "Cannot initialize client (%d): %s", rc, gsasl_strerror(rc));
120 }
121
122 std::string password = Base64Encode(token.getPassword());
123 std::string identifier = Base64Encode(token.getIdentifier());
124 gsasl_property_set(session, GSASL_PASSWORD, password.c_str());
125 gsasl_property_set(session, GSASL_AUTHID, identifier.c_str());
126 gsasl_property_set(session, GSASL_HOSTNAME, auth.serverid().c_str());
127 gsasl_property_set(session, GSASL_SERVICE, auth.protocol().c_str());
128}
129
130std::string SaslClient::evaluateChallenge(const std::string & challenge) {
131 int rc;
132 char * output = NULL;
133 size_t outputSize;
134 std::string retval;
135 rc = gsasl_step(session, &challenge[0], challenge.size(), &output,
136 &outputSize);
137
138 if (rc == GSASL_NEEDS_MORE || rc == GSASL_OK) {
139 retval.resize(outputSize);
140 memcpy(&retval[0], output, outputSize);
141
142 if (output) {
143 free(output);
144 }
145 } else {
146 if (output) {
147 free(output);
148 }
149
150 THROW(AccessControlException, "Failed to evaluate challenge: %s", gsasl_strerror(rc));
151 }
152
153 if (rc == GSASL_OK) {
154 complete = true;
155 }
156
157 return retval;
158}
159
160bool SaslClient::isComplete() {
161 return complete;
162}
163
164}
165}
166
167