1 jsafrane 1.1 //%LICENSE////////////////////////////////////////////////////////////////
2 //
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 jsafrane 1.1 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //////////////////////////////////////////////////////////////////////////
29 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include <Pegasus/Common/Config.h>
33 #include "Executor.h"
34 #include "Negotiate.h"
35 #include "Tracer.h"
36 #include "Base64.h"
37
38 PEGASUS_NAMESPACE_BEGIN
39
40 static const char NEGOTIATE_GET_NAME_FAILED_KEY [] =
41 "Common.Negotiate NEGOTIATE_GET_NAME_FAILURE";
42
43 jsafrane 1.1 static const char NEGOTIATE_GET_NAME_FAILED[] =
44 "Cannot read user name for Negotiate request.";
45
46 static const char NEGOTIATE_GET_NAME_RELEASE_FAILED_KEY [] =
47 "Common.Negotiate NEGOTIATE_GET_NAME_RELEASE_FAILURE";
48
49 static const char NEGOTIATE_GET_NAME_RELEASE_FAILED[] =
50 "Cannot release user name for Negotiate request.";
51
52 static const char NEGOTIATE_GET_NAME_SUCCESS_KEY [] =
53 "Common.Negotiate NEGOTIATE_GET_NAME_RELEASE_SUCCESS";
54
55 static const char NEGOTIATE_GET_NAME_SUCCESS[] =
56 "Got user name $0 from Negotiate request.";
57
58 static const char NEGOTIATE_SERVICE_NAME[] = "cimom@";
59
60 static gss_OID_desc gss_mech_spnego = {
61 6,
62 (char *)"\x2b\x06\x01\x05\x05\x02"
63 };
64 jsafrane 1.1
65 String getNegotiateError(uint32_t major, uint32_t minor)
66 {
67 gss_buffer_desc text;
68 uint32_t maj, min;
69 uint32_t msg_ctx = 0;
70
71 bool first = true;
72 String msg;
73 do {
74 maj = gss_display_status(&min, major, GSS_C_GSS_CODE, GSS_C_NO_OID,
75 &msg_ctx, &text);
76 if (maj != GSS_S_COMPLETE)
77 return msg;
78 if (!first)
79 msg.append(", ");
80 msg.append((const char*)text.value, text.length);
81 first = false;
82 } while (msg_ctx != 0);
83
84 do {
85 jsafrane 1.1 maj = gss_display_status(&min, minor, GSS_C_MECH_CODE, GSS_C_NO_OID,
86 &msg_ctx, &text);
87 if (maj != GSS_S_COMPLETE)
88 return msg;
89 if (!first)
90 msg.append(", ");
91 msg.append((const char*)text.value, text.length);
92 first = false;
93 } while (msg_ctx != 0);
94
95 return msg;
96 }
97
98 NegotiateServerSession::NegotiateServerSession()
99 : _challenge(String::EMPTY)
100 {
101 PEG_METHOD_ENTER(
102 TRC_AUTHENTICATION, "NegotiateServerSession::NegotiateServerSession");
103
104 _ctx = GSS_C_NO_CONTEXT;
105
106 jsafrane 1.1 PEG_METHOD_EXIT();
107 }
108
109 NegotiateServerSession::~NegotiateServerSession()
110 {
111 PEG_METHOD_ENTER(
112 TRC_AUTHENTICATION, "NegotiateServerSession::~NegotiateServerSession");
113 uint32_t min;
114 gss_delete_sec_context(&min, &_ctx, GSS_C_NO_BUFFER);
115 PEG_METHOD_EXIT();
116 }
117
118 NegotiateAuthenticationStatus NegotiateServerSession::authenticate(
119 const String &authorization,
120 String &userName,
121 Boolean mapToLocalName)
122 {
123 PEG_METHOD_ENTER(
124 TRC_AUTHENTICATION, "NegotiateServerSession::authenticate");
125
126 // decode the authorization data
127 jsafrane 1.1 Buffer data;
128 data.append((const char*) authorization.getCString(), authorization.size());
129 Buffer decodedData = Base64::decode( data );
130
131 // collect GSSAPI input and output arguments
132 uint32_t flags = 0, maj, min = 0, unused;
133 gss_name_t client = GSS_C_NO_NAME;
134 gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
135 gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
136 gss_OID mech_type;
137 input.value = decodedData.getContentPtr();
138 input.length = decodedData.size();
139
140 maj = gss_accept_sec_context(
141 &min, // minor error code
142 &_ctx, // gssapi context
143 GSS_C_NO_CREDENTIAL, // server's credentials
144 &input, // token from WWW-Authenticate:
145 GSS_C_NO_CHANNEL_BINDINGS, // input channel bindings
146 &client, // out: client's name
147 &mech_type, // out: authentication type
148 jsafrane 1.1 &output, // out: token for Authorization:
149 &flags, // out: flags
150 NULL, // out: context lifetime
151 NULL); // out: delegated credentials
152
153 userName = parseUserName(client, mech_type, mapToLocalName);
154 gss_release_name(&unused, &client);
155
156 NegotiateAuthenticationStatus status;
157
158 if (GSS_ERROR(maj))
159 {
160 PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL3,
161 "NegotiateServerSession::authenticate:"\
162 " GSSAPI failed, reseting authentication."));
163
164 // reset the GSSAPI context, in case the user tries it again
165 gss_delete_sec_context(&unused, &_ctx, GSS_C_NO_BUFFER);
166 _ctx = GSS_C_NO_CONTEXT;
167 // no challenge in the next HTTP response
168 _challenge = String::EMPTY;
169 jsafrane 1.1
170 // TODO: log the gssapi error message
171 status = NEGOTIATE_FAILED;
172 }
173 else
174 {
175 // no error so far
176 // remember the challenge to send (already base64-encoded)
177 if (output.length > 0)
178 {
179 Buffer outputBuf((const char*) output.value, output.length);
180 Buffer encodedBuf = Base64::encode(outputBuf);
181 _challenge.assign(encodedBuf.getData(), encodedBuf.size());
182 gss_release_buffer(&min, &output);
183 }
184 else
185 {
186 // no challenge in the next HTTP response
187 _challenge = String::EMPTY;
188 }
189
190 jsafrane 1.1 if (maj == GSS_S_COMPLETE)
191 {
192 PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL3,
193 "NegotiateServerSession::authenticate:"\
194 " GSSAPI finished successfully."));
195 status = NEGOTIATE_SUCCESS;
196 }
197 else
198 {
199 PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL3,
200 "NegotiateServerSession::authenticate:"\
201 " GSSAPI continues."));
202 status = NEGOTIATE_CONTINUE;
203 }
204 }
205
206 // GSSAPI does not do any access control, do it now
207 if (status == NEGOTIATE_SUCCESS)
208 {
209 int ret = Executor::validateUser((const char*) userName.getCString());
210 if (ret != 0)
211 jsafrane 1.1 {
212 PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL3,
213 "NegotiateServerSession::authenticate:"\
214 " authorization failed."));
215
216 // reset the GSSAPI context, in case the user tries it again
217 gss_delete_sec_context(&unused, &_ctx, GSS_C_NO_BUFFER);
218 _ctx = GSS_C_NO_CONTEXT;
219 // no challenge in the next HTTP response
220 _challenge = String::EMPTY;
221 status = NEGOTIATE_FAILED;
222 // TODO: log access error
223 }
224 }
225
226 PEG_METHOD_EXIT();
227 return status;
228 }
229
230 String NegotiateServerSession::parseUserName(gss_name_t client,
231 gss_OID mech_type, Boolean mapToLocalName)
232 jsafrane 1.1 {
233 PEG_METHOD_ENTER(
234 TRC_AUTHENTICATION, "NegotiateServerSession::parseUserName");
235
236 uint32_t maj, min;
237 gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
238 gss_OID oid;
239
240 if (mapToLocalName)
241 maj = gss_localname(&min, client, mech_type, &output);
242 else
243 maj = gss_display_name(&min, client, &output, &oid);
244 if (maj != GSS_S_COMPLETE)
245 {
246 Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
247 Logger::INFORMATION,
248 MessageLoaderParms(
249 NEGOTIATE_GET_NAME_FAILED_KEY,
250 NEGOTIATE_GET_NAME_FAILED));
251 PEG_METHOD_EXIT();
252 return String::EMPTY;
253 jsafrane 1.1 }
254
255 String userName((const char*) output.value, (unsigned int) output.length);
256
257 Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
258 Logger::TRACE,
259 MessageLoaderParms(
260 NEGOTIATE_GET_NAME_SUCCESS_KEY,
261 NEGOTIATE_GET_NAME_SUCCESS, userName));
262
263 maj = gss_release_buffer(&min, &output);
264 if (maj != GSS_S_COMPLETE)
265 {
266 Logger::put_l(Logger::STANDARD_LOG, System::CIMSERVER,
267 Logger::INFORMATION,
268 MessageLoaderParms(
269 NEGOTIATE_GET_NAME_RELEASE_FAILED_KEY,
270 NEGOTIATE_GET_NAME_RELEASE_FAILED));
271 }
272
273 PEG_METHOD_EXIT();
274 jsafrane 1.1 return userName;
275 }
276
277
278
279
280
281
282 NegotiateClientSession::NegotiateClientSession(String hostname)
283 : _challenge(String::EMPTY)
284 {
285 PEG_METHOD_ENTER(
286 TRC_AUTHENTICATION, "NegotiateClientSession::NegotiateClientSession");
287
288 _ctx = GSS_C_NO_CONTEXT;
289
290 // translate hostname to gss_name_t (cimom@<hostname>)
291 gss_buffer_desc input;
292 Buffer buf(NEGOTIATE_SERVICE_NAME, sizeof(NEGOTIATE_SERVICE_NAME)-1);
293 buf.append(hostname.getCString(), hostname.size()+1);
294 input.value = buf.getContentPtr();
295 jsafrane 1.1 input.length = buf.size();
296
297 uint32_t min=0, maj;
298 maj = gss_import_name(&min, &input, GSS_C_NT_HOSTBASED_SERVICE, &_service);
299 if (GSS_ERROR(maj))
300 {
301 String msg = getNegotiateError(maj, min);
302 MessageLoaderParms parms(
303 "Common.Negotiate."
304 "NEGOTIATE_CLIENT_SESSION_FAILED_TO_INITIALIZE",
305 "Client authentication handler for Negotiate failed to "
306 "initialize properly: %s.", (const char *) msg.getCString());
307 Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::SEVERE,
308 parms);
309 throw Exception(parms);
310 }
311 PEG_METHOD_EXIT();
312 }
313
314 NegotiateClientSession::~NegotiateClientSession()
315 {
316 jsafrane 1.1 PEG_METHOD_ENTER(
317 TRC_AUTHENTICATION, "NegotiateClientSession::~NegotiateClientSession");
318
319 uint32_t min;
320 gss_delete_sec_context(&min, &_ctx, GSS_C_NO_BUFFER);
321 gss_release_name(&min, &_service);
322
323 PEG_METHOD_EXIT();
324 }
325
326 /**
327 * Return <data> for 'WWW-Authenticate: Negotiate <data>' header,
328 * already base64 encoded.
329 * @return The data for WWW-Authenticate header.
330 */
331 String NegotiateClientSession::buildRequestAuthData()
332 {
333 PEG_METHOD_ENTER(
334 TRC_AUTHENTICATION, "NegotiateClientSession::buildRequestAuthData");
335
336 // decode previous challenge from base64
337 jsafrane 1.1
338 gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
339 if (_challenge.size() > 0)
340 {
341 Buffer data;
342 data.append((const char*) _challenge.getCString(), _challenge.size());
343 Buffer decodedData = Base64::decode( data );
344 input.value = decodedData.getContentPtr();
345 input.length = decodedData.size();
346 }
347
348 // collect GSSAPI input and output arguments
349 uint32_t flags = 0, maj, min = 0;
350 gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
351
352 maj = gss_init_sec_context(
353 &min, // minor error code
354 GSS_C_NO_CREDENTIAL, // client credentials
355 &_ctx, // gssapi context
356 _service, // remote service name
357 &gss_mech_spnego, // requested authentication mechanism
358 jsafrane 1.1 GSS_C_REPLAY_FLAG, // requested flags
359 0, // requested token lifetime
360 GSS_C_NO_CHANNEL_BINDINGS, // input channel bindings
361 &input, // token from 401 Unauthorized response
362 NULL, // out: actual authentication mechanism
363 &output, // out: token for WWW-Authenticate:
364 &flags, // out: output flags
365 NULL); // out: actual token lifetime
366
367 String authentication;
368 if (GSS_ERROR(maj))
369 {
370 // reset the GSSAPI context and challenge
371 _challenge = String::EMPTY;
372
373 String msg = getNegotiateError(maj, min);
374 PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL2,
375 "NegotiateClientSession::buildRequestAuthData GSSAPI error %s",
376 (const char *) msg.getCString()));
377 gss_delete_sec_context(&min, &_ctx, GSS_C_NO_BUFFER);
378 _ctx = GSS_C_NO_CONTEXT;
379 jsafrane 1.1 }
380 else
381 {
382 // no error so far
383 if (output.length > 0)
384 {
385 Buffer outputBuf((const char*) output.value, output.length);
386 Buffer encodedBuf = Base64::encode(outputBuf);
387 authentication.assign(encodedBuf.getData(), encodedBuf.size());
388 gss_release_buffer(&min, &output);
389 PEG_TRACE((TRC_AUTHENTICATION, Tracer::LEVEL2,
390 "NegotiateClientSession::buildRequestAuthData"
391 " sending response %s\n",
392 (const char*) authentication.getCString()));
393 }
394 }
395
396 PEG_METHOD_EXIT();
397 return authentication;
398 }
399
400 jsafrane 1.1 PEGASUS_NAMESPACE_END
401
402
|