Drizzled Public API Documentation

auth_http.cc
1 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2009 Sun Microsystems, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <config.h>
21 
22 #include <curl/curl.h>
23 
24 #include <string>
25 #include <cassert>
26 #include <boost/program_options.hpp>
28 #include <drizzled/identifier.h>
29 #include <drizzled/plugin/authentication.h>
30 #include <drizzled/gettext.h>
31 namespace po= boost::program_options;
32 using namespace drizzled;
33 using namespace std;
34 
35 static size_t curl_cb_read(void *ptr, size_t size, size_t nmemb, void *stream)
36 {
37  (void) ptr;
38  (void) stream;
39  return (size * nmemb);
40 }
41 
42 
44 {
45  CURLcode rv;
46  CURL *curl_handle;
47  const std::string auth_url;
48 public:
49  Auth_http(std::string name_arg, const std::string &url_arg) :
51  auth_url(url_arg)
52  {
53  // we are trusting that plugin initializers are called singlethreaded at startup
54  // if something else also calls curl_global_init() in a threadrace while we are here,
55  // we will crash the server.
56  curl_handle= curl_easy_init();
57 
58  // turn off curl stuff that might mess us up
59  rv= curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0);
60  rv= curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
61  rv= curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
62 
63  // do a HEAD instead of a default GET
64  rv= curl_easy_setopt(curl_handle, CURLOPT_NOBODY, 1);
65 
66  // set the read callback. this shouldnt get called, because we are doing a HEAD
67  rv= curl_easy_setopt(curl_handle, CURLOPT_READFUNCTION, curl_cb_read);
68  }
69 
70  ~Auth_http()
71  {
72  curl_easy_cleanup(curl_handle);
73  curl_global_cleanup();
74  }
75 
76  virtual bool authenticate(const identifier::User &sctx, const string &password)
77  {
78  long http_response_code;
79 
80  assert(sctx.username().c_str());
81 
82  // set the parameters: url, username, password
83  rv= curl_easy_setopt(curl_handle, CURLOPT_URL, auth_url.c_str());
84 #if defined(HAVE_CURLOPT_USERNAME)
85 
86  rv= curl_easy_setopt(curl_handle, CURLOPT_USERNAME,
87  sctx.username().c_str());
88  rv= curl_easy_setopt(curl_handle, CURLOPT_PASSWORD, password.c_str());
89 
90 #else
91 
92  string userpwd(sctx.username());
93  userpwd.append(":");
94  userpwd.append(password);
95  rv= curl_easy_setopt(curl_handle, CURLOPT_USERPWD, userpwd.c_str());
96 
97 #endif /* defined(HAVE_CURLOPT_USERNAME) */
98 
99  // do it
100  rv= curl_easy_perform(curl_handle);
101 
102  // what did we get? goes into http_response_code
103  rv= curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_response_code);
104 
105  // so here is an interesting question.
106  // return true if the response_code is 2XX, or return false if its 4XX
107  // for now, return false for 401, true otherwise
108  // this means that if the url breaks, then anyone can log in
109  // this might be the wrong thing
110 
111  if (http_response_code == 401)
112  return false;
113  return true;
114  }
115 };
116 
117 Auth_http* auth= NULL;
118 
119 static int initialize(drizzled::module::Context &context)
120 {
121  const module::option_map &vm= context.getOptions();
122 
123  /*
124  * Per libcurl manual, in multi-threaded applications, curl_global_init() should
125  * be called *before* curl_easy_init()...which is called in Auto_http's
126  * constructor.
127  */
128  if (curl_global_init(CURL_GLOBAL_NOTHING) != 0)
129  return 1;
130 
131  const string auth_url(vm["url"].as<string>());
132  if (auth_url.size() == 0)
133  {
134  errmsg_printf(error::ERROR,
135  _("auth_http plugin loaded but required option url not "
136  "specified. Against which URL are you intending on "
137  "authenticating?\n"));
138  return 1;
139  }
140 
141  auth= new Auth_http("auth_http", auth_url);
142  context.add(auth);
143  context.registerVariable(new sys_var_const_string_val("url", auth_url));
144 
145  return 0;
146 }
147 
148 static void init_options(drizzled::module::option_context &context)
149 {
150  context("url", po::value<string>()->default_value(""),
151  N_("URL for HTTP Auth check"));
152 }
153 
154 
155 DRIZZLE_DECLARE_PLUGIN
156 {
157  DRIZZLE_VERSION_ID,
158  "auth-http",
159  "0.1",
160  "Mark Atwood",
161  N_("Authenication against a web server using HTTP"),
162  PLUGIN_LICENSE_GPL,
163  initialize,
164  NULL,
165  init_options
166 }
167 DRIZZLE_DECLARE_PLUGIN_END;