diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-01-01 13:47:44 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-01-01 13:47:44 +0000 |
commit | 3af8f4ce646d29cd5942a1e3dda3b7ed03a82af6 (patch) | |
tree | fe9ede8fc028e6b7ebd2c683be623214b365f1a7 /doc/chapters | |
parent | 964326eb5348b5acf7d1cff7fb2f3c0d44ff4716 (diff) | |
download | libmicrohttpd-3af8f4ce646d29cd5942a1e3dda3b7ed03a82af6.tar.gz libmicrohttpd-3af8f4ce646d29cd5942a1e3dda3b7ed03a82af6.zip |
updating docs
Diffstat (limited to 'doc/chapters')
-rw-r--r-- | doc/chapters/basicauthentication.inc | 148 | ||||
-rw-r--r-- | doc/chapters/tlsauthentication.inc | 18 |
2 files changed, 65 insertions, 101 deletions
diff --git a/doc/chapters/basicauthentication.inc b/doc/chapters/basicauthentication.inc index 2b68fc4c..8c7c241c 100644 --- a/doc/chapters/basicauthentication.inc +++ b/doc/chapters/basicauthentication.inc | |||
@@ -69,112 +69,62 @@ Let us assume we had only files not intended to be handed out without the correc | |||
69 | so every "GET" request will be challenged. | 69 | so every "GET" request will be challenged. |
70 | @emph{RFC 2617} describes how the server shall ask for authentication by adding a | 70 | @emph{RFC 2617} describes how the server shall ask for authentication by adding a |
71 | @emph{WWW-Authenticate} response header with the name of the @emph{realm} protected. | 71 | @emph{WWW-Authenticate} response header with the name of the @emph{realm} protected. |
72 | 72 | MHD can generate and queue such a failure response for you using | |
73 | We let an extra function function do this. | 73 | the @code{MHD_queue_basic_auth_fail_response} API. The only thing you need to do |
74 | is construct a response with the error page to be shown to the user | ||
75 | if he aborts basic authentication. But first, you should check if the | ||
76 | proper credentials were already supplied using the | ||
77 | @code{MHD_basic_auth_get_username_password} call. | ||
78 | |||
79 | Your code would then look like this: | ||
74 | @verbatim | 80 | @verbatim |
75 | static int | 81 | static int |
76 | ask_for_authentication (struct MHD_Connection *connection, const char *realm) | 82 | answer_to_connection (void *cls, struct MHD_Connection *connection, |
83 | const char *url, const char *method, | ||
84 | const char *version, const char *upload_data, | ||
85 | size_t *upload_data_size, void **con_cls) | ||
77 | { | 86 | { |
78 | int ret; | 87 | char *user; |
88 | char *pass; | ||
89 | int fail; | ||
79 | struct MHD_Response *response; | 90 | struct MHD_Response *response; |
80 | char *headervalue; | 91 | |
81 | const char *strbase = "Basic realm="; | 92 | if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) |
82 | 93 | return MHD_NO; | |
83 | response = MHD_create_response_from_data (0, NULL, MHD_NO, MHD_NO); | 94 | if (NULL == *con_cls) |
84 | if (!response) return MHD_NO; | 95 | { |
85 | 96 | *con_cls = connection; | |
86 | headervalue = malloc (strlen (strbase) + strlen (realm) + 1); | 97 | return MHD_YES; |
87 | if (!headervalue) return MHD_NO; | 98 | } |
88 | 99 | pass = NULL; | |
89 | strcpy (headervalue, strbase); | 100 | user = MHD_basic_auth_get_username_password (connection, &pass); |
90 | strcat (headervalue, realm); | 101 | fail = ( (user == NULL) || |
91 | 102 | (0 != strcmp (user, "root")) || | |
92 | ret = MHD_add_response_header (response, "WWW-Authenticate", headervalue); | 103 | (0 != strcmp (pass, "pa$$w0rd") ) ); |
93 | free (headervalue); | 104 | if (user != NULL) free (user); |
94 | if (!ret) {MHD_destroy_response (response); return MHD_NO;} | 105 | if (pass != NULL) free (pass); |
95 | 106 | if (fail) | |
96 | ret = MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response); | 107 | { |
108 | const char *page = "<html><body>Go away.</body></html>"; | ||
109 | response = | ||
110 | MHD_create_response_from_data (strlen (page), (void *) page, MHD_NO, | ||
111 | MHD_NO); | ||
112 | ret = MHD_queue_basic_auth_fail_response (connection, | ||
113 | "my realm", | ||
114 | response); | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | const char *page = "<html><body>A secret.</body></html>"; | ||
119 | response = | ||
120 | MHD_create_response_from_data (strlen (page), (void *) page, MHD_NO, | ||
121 | MHD_NO); | ||
122 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
123 | } | ||
97 | MHD_destroy_response (response); | 124 | MHD_destroy_response (response); |
98 | return ret; | 125 | return ret; |
99 | } | 126 | } |
100 | @end verbatim | 127 | @end verbatim |
101 | @noindent | ||
102 | |||
103 | @code{#define} the realm name according to your own taste, e.g. "Maintenance" or "Area51" but | ||
104 | it will need to have extra quotes. | ||
105 | |||
106 | Since the client may send the authentication right away, it would be wrong to ask for | ||
107 | it without checking the request's header--where the authentication is expected to be found. | ||
108 | |||
109 | @heading Authentication in detail | ||
110 | Checking @emph{RFC 2617} again, we find that the client will pack the username and password, by | ||
111 | whatever means he might have obtained them, in a line separated by a colon---and then encodes | ||
112 | them to @emph{Base64}. The actual implementation of this encoding are not within the scope of | ||
113 | this tutorial although a working function is included in the complete source file of the example. | ||
114 | |||
115 | An unencoded word describing the authentication method (here "Basic") will precede the code | ||
116 | and the resulting line is the value of a request header of the type "Authorization". | ||
117 | |||
118 | This header line thus is of interest to the function checking a connection for a given username/password: | ||
119 | @verbatim | ||
120 | static int | ||
121 | is_authenticated (struct MHD_Connection *connection, | ||
122 | const char *username, const char *password) | ||
123 | { | ||
124 | const char *headervalue; | ||
125 | ... | ||
126 | |||
127 | headervalue = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, | ||
128 | "Authorization"); | ||
129 | if (NULL == headervalue) return 0; | ||
130 | @end verbatim | ||
131 | @noindent | ||
132 | |||
133 | where, firstly, the authentication method will be checked. | ||
134 | @verbatim | ||
135 | const char *strbase = "Basic "; | ||
136 | ... | ||
137 | if (0 != strncmp (headervalue, strbase, strlen (strbase))) return 0; | ||
138 | @end verbatim | ||
139 | @noindent | ||
140 | |||
141 | Of course, we could decode the passed credentials in the next step and compare them directly to | ||
142 | the given strings. But as this would involve string parsing, which is more complicated then string | ||
143 | composing, it is done the other way around---the clear text credentials will be encoded to @emph{Base64} | ||
144 | and then compared against the headerline. The authentication method string will be left out here as | ||
145 | it has been checked already at this point. | ||
146 | @verbatim | ||
147 | char *expected_b64, *expected; | ||
148 | int authenticated; | ||
149 | |||
150 | ... | ||
151 | strcpy (expected, username); | ||
152 | strcat (expected, ":"); | ||
153 | strcat (expected, password); | ||
154 | |||
155 | expected_b64 = string_to_base64 (expected); | ||
156 | if (NULL == expected_b64) return 0; | ||
157 | |||
158 | strcpy (expected, strbase); | ||
159 | authenticated = (strcmp (headervalue + strlen (strbase), expected_b64) == 0); | ||
160 | |||
161 | free (expected_b64); | ||
162 | |||
163 | return authenticated; | ||
164 | } | ||
165 | @end verbatim | ||
166 | @noindent | ||
167 | |||
168 | These two functions---together with a response function in case of positive authentication doing little | ||
169 | new---allow the rest of the callback function to be rather short. | ||
170 | @verbatim | ||
171 | if (!is_authenticated (connection, USER, PASSWORD)) | ||
172 | return ask_for_authentication (connection, REALM); | ||
173 | |||
174 | return secret_page (connection); | ||
175 | } | ||
176 | @end verbatim | ||
177 | @noindent | ||
178 | 128 | ||
179 | See the @code{examples} directory for the complete example file. | 129 | See the @code{examples} directory for the complete example file. |
180 | 130 | ||
diff --git a/doc/chapters/tlsauthentication.inc b/doc/chapters/tlsauthentication.inc index 4f9c4443..278a3ba5 100644 --- a/doc/chapters/tlsauthentication.inc +++ b/doc/chapters/tlsauthentication.inc | |||
@@ -135,8 +135,22 @@ both of uncritically @emph{HTTP} parts and secured @emph{HTTPS}. | |||
135 | You can also use MHD to authenticate the client via SSL/TLS certificates | 135 | You can also use MHD to authenticate the client via SSL/TLS certificates |
136 | (as an alternative to using the password-based Basic or Digest authentication). | 136 | (as an alternative to using the password-based Basic or Digest authentication). |
137 | To do this, you will need to link your application against @emph{gnutls}. | 137 | To do this, you will need to link your application against @emph{gnutls}. |
138 | For this, you first need to obtain the raw GnuTLS session handle from | 138 | Next, when you start the MHD daemon, you must specify the root CA that you're |
139 | @emph{MHD} using @code{MHD_get_connection_info}. | 139 | willing to trust: |
140 | @verbatim | ||
141 | daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_SSL, | ||
142 | PORT, NULL, NULL, | ||
143 | &answer_to_connection, NULL, | ||
144 | MHD_OPTION_HTTPS_MEM_KEY, key_pem, | ||
145 | MHD_OPTION_HTTPS_MEM_CERT, cert_pem, | ||
146 | MHD_OPTION_HTTPS_MEM_TRUST, root_ca_pem, | ||
147 | MHD_OPTION_END); | ||
148 | @end verbatim | ||
149 | |||
150 | With this, you can then obtain client certificates for each session. | ||
151 | In order to obtain the identity of the client, you first need to | ||
152 | obtain the raw GnuTLS session handle from @emph{MHD} using | ||
153 | @code{MHD_get_connection_info}. | ||
140 | 154 | ||
141 | @verbatim | 155 | @verbatim |
142 | #include <gnutls/gnutls.h> | 156 | #include <gnutls/gnutls.h> |