(file) Return to Negotiate.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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              

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2