2 #define _POSIX_SOURCE /* For getaddrinfo(3) */
6 #define _BSD_SOURCE /* For NI_MAXHOST */
9 #include "../test-tools.h"
16 #include <sys/types.h>
17 #include <sys/socket.h>
24 const char *server_error
= NULL
;
26 static const char *as_path_hotp
= "/as/processLogin?type=hotp&uri=";
27 static const char *as_path_sendsms
= "/as/processLogin?type=totp&sendSms=true&uri=";
28 static const char *as_path_dontsendsms
= "/as/processLogin?type=totp&uri=";
29 static const char *as_path_logout
= "/as/processLogout?uri=";
30 static const char *ws_path
= "/apps/DS/dz";
32 static const char *authorization_cookie_name
= "IPCZ-X-COOKIE";
33 static char *authorization_cookie_value
= NULL
;
35 /* Save pointer to static error message if not yet set */
36 void set_server_error(const char *message
) {
37 if (server_error
== NULL
) {
38 server_error
= message
;
43 /* Creates listening TCP socket on localhost.
44 * Returns the socket descriptor or -1. */
45 int listen_on_socket(void) {
47 struct addrinfo hints
;
48 struct addrinfo
*addresses
, *address
;
51 memset(&hints
, 0, sizeof(hints
));
52 hints
.ai_family
= AF_UNSPEC
;
53 hints
.ai_socktype
= SOCK_STREAM
;
54 retval
= getaddrinfo("localhost", NULL
, &hints
, &addresses
);
56 set_server_error("Could not resolve `localhost'");
60 for (address
= addresses
; address
!= NULL
; address
= address
->ai_next
) {
61 fd
= socket(address
->ai_family
, address
->ai_socktype
,
62 address
->ai_protocol
);
63 if (fd
== -1) continue;
65 retval
= bind(fd
, address
->ai_addr
, address
->ai_addrlen
);
66 if (retval
!= 0) continue;
68 retval
= listen(fd
, 0);
70 freeaddrinfo(addresses
);
75 freeaddrinfo(addresses
);
76 set_server_error("Could not start listening on TCP/localhost");
81 /* Format socket address as printable string.
82 * @return allocated string or NULL in case of error. */
83 char *socket2address(int socket
) {
84 struct sockaddr_storage storage
;
85 socklen_t length
= (socklen_t
) sizeof(storage
);
86 char host
[NI_MAXHOST
];
87 char service
[NI_MAXSERV
];
90 if (-1 == getsockname(socket
, (struct sockaddr
*)&storage
, &length
)) {
91 set_server_error("Could not get address of server socket");
95 if (0 != getnameinfo((struct sockaddr
*)&storage
, length
,
96 host
, sizeof(host
), service
, sizeof(service
),
97 NI_NUMERICHOST
|NI_NUMERICSERV
)) {
98 set_server_error("Could not resolve address of server socket");
102 if (-1 == test_asprintf(&address
,
103 (strchr(host
, ':') == NULL
) ? "%s:%s" : "[%s]:%s",
105 set_server_error("Could not format server address");
113 /* Process ISDS WS ping */
114 static void do_ws(int client_socket
, const struct http_request
*request
) {
115 if (request
->method
!= HTTP_METHOD_POST
) {
116 http_send_response_400(client_socket
,
117 "Regular ISDS web service request must be POST");
121 soap(client_socket
, request
->body
, request
->body_length
);
125 /* Do the server protocol.
126 * @server_socket is listening TCP socket of the server
127 * @server_arguments is pointer to structure:
128 * Never returns. Terminates by exit(). */
129 void server_basic_authentication(int server_socket
,
130 const void *server_arguments
) {
132 const struct arguments_basic_authentication
*arguments
=
133 (const struct arguments_basic_authentication
*) server_arguments
;
134 struct http_request
*request
= NULL
;
137 if (arguments
== NULL
) {
138 close(server_socket
);
142 while (0 <= (client_socket
= accept(server_socket
, NULL
, NULL
))) {
143 fprintf(stderr
, "Connection accepted\n");
144 error
= http_read_request(client_socket
, &request
);
146 fprintf(stderr
, "Error while reading request\n");
147 if (error
== HTTP_ERROR_CLIENT
)
148 http_send_response_400(client_socket
, "Error in request");
150 http_send_response_500(client_socket
,
151 "Error while reading request");
152 close(client_socket
);
156 if (request
->method
== HTTP_METHOD_POST
) {
157 /* Only POST requests are used in Basic authentication mode */
158 if (arguments
->username
!= NULL
) {
159 if (http_client_authenticates(request
)) {
160 switch(http_authenticate_basic(request
,
161 arguments
->username
, arguments
->password
)) {
162 case HTTP_ERROR_SUCCESS
:
163 do_ws(client_socket
, request
);
165 case HTTP_ERROR_CLIENT
:
166 if (arguments
->isds_deviations
)
167 http_send_response_401_basic(client_socket
);
169 http_send_response_403(client_socket
);
172 http_send_response_500(client_socket
,
173 "Server error while verifying Basic "
177 http_send_response_401_basic(client_socket
);
180 do_ws(client_socket
, request
);
183 /* HTTP method unsupported per ISDS specification */
184 http_send_response_400(client_socket
,
185 "Only POST method is allowed");
187 http_request_free(&request
);
190 close(client_socket
);
193 close(server_socket
);
198 /* Process first phase of TOTP request */
199 static void do_as_sendsms(int client_socket
, const struct http_request
*request
,
200 const struct arguments_otp_authentication
*arguments
) {
201 if (arguments
== NULL
) {
202 http_send_response_500(client_socket
,
203 "Third argument of do_as_sendsms() is NULL");
207 if (request
->method
!= HTTP_METHOD_POST
) {
208 http_send_response_400(client_socket
,
209 "First phase TOTP request must be POST");
213 if (!http_client_authenticates(request
)) {
214 http_send_response_401_otp(client_socket
,
216 "authentication.error.userIsNotAuthenticated",
217 "Client did not send any authentication header");
221 switch(http_authenticate_basic(request
,
222 arguments
->username
, arguments
->password
)) {
223 case HTTP_ERROR_SUCCESS
: {
225 char *uri
= strstr(request
->uri
, "&uri=");
227 http_send_response_400(client_socket
,
228 "Missing uri parameter in Request URI");
232 /* Build new location for second OTP phase */
233 char *location
= NULL
;
234 if (-1 == test_asprintf(&location
, "%s%s", as_path_dontsendsms
, uri
)) {
235 http_send_response_500(client_socket
,
236 "Could not build new localtion for "
240 char *terminator
= strchr(uri
, '&');
241 if (NULL
!= terminator
)
242 location
[strlen(as_path_dontsendsms
) + (uri
- terminator
)] = '\0';
243 http_send_response_302_totp(client_socket
,
244 "authentication.info.totpSended",
245 "=?UTF-8?B?SmVkbm9yw6F6b3bDvSBrw7NkIG9kZXNsw6FuLg==?=",
250 case HTTP_ERROR_CLIENT
:
251 if (arguments
->isds_deviations
)
252 http_send_response_401_otp(client_socket
,
254 "authentication.error.userIsNotAuthenticated",
255 " Retry: Bad user name or password in first OTP phase.\r\n"
256 " This is very long header\r\n"
257 " which should span to more lines.\r\n"
258 " Surrounding LWS are meaning-less. ");
260 http_send_response_403(client_socket
);
263 http_send_response_500(client_socket
,
264 "Could not verify Basic authentication");
269 /* Return static string representation of HTTP OTP authentication method.
270 * Or NULL in case of error. */
271 static const char *auth_otp_method2string(enum auth_otp_method method
) {
273 case AUTH_OTP_HMAC
: return "hotp";
274 case AUTH_OTP_TIME
: return "totp";
275 default: return NULL
;
280 /* Process second phase of OTP request */
281 static void do_as_phase_two(int client_socket
, const struct http_request
*request
,
282 const struct arguments_otp_authentication
*arguments
) {
283 if (arguments
== NULL
) {
284 http_send_response_500(client_socket
,
285 "Third argument of do_as_phase_two() is NULL");
289 if (request
->method
!= HTTP_METHOD_POST
) {
290 http_send_response_400(client_socket
,
291 "Second phase OTP request must be POST");
295 if (!http_client_authenticates(request
)) {
296 http_send_response_401_otp(client_socket
,
297 auth_otp_method2string(arguments
->method
),
298 "authentication.error.userIsNotAuthenticated",
299 "Client did not send any authentication header");
303 switch(http_authenticate_otp(request
,
304 arguments
->username
, arguments
->password
, arguments
->otp
)) {
305 case HTTP_ERROR_SUCCESS
: {
307 char *uri
= strstr(request
->uri
, "&uri=");
309 http_send_response_400(client_socket
,
310 "Missing uri parameter in Request URI");
314 /* Build new location for final request */
315 char *location
= NULL
;
316 if (NULL
== (location
= strdup(uri
))) {
317 http_send_response_500(client_socket
,
318 "Could not build new location for final request");
321 char *terminator
= strchr(location
, '&');
322 if (NULL
!= terminator
)
324 /* Generate pseudo-random cookie value. This is to prevent
325 * client from reusing the cookie accidentally. We use the
326 * same seed to get reproducible tests. */
327 if (-1 == test_asprintf(&authorization_cookie_value
, "%d",
329 http_send_response_500(client_socket
,
330 "Could not generate cookie value");
334 /* XXX: Add Path parameter to cookie, otherwise
335 * different paths will not match.
336 * FIXME: Domain argument does not work with cURL. Report a bug. */
337 http_send_response_302_cookie(client_socket
,
338 authorization_cookie_name
,
339 authorization_cookie_value
,
340 /*http_find_host(request)*/NULL
,
346 case HTTP_ERROR_CLIENT
:
347 if (arguments
->isds_deviations
)
348 http_send_response_401_otp(client_socket
,
349 auth_otp_method2string(arguments
->method
),
350 "authentication.error.userIsNotAuthenticated",
351 " Retry: Bad user name or password in second OTP phase.\r\n"
352 " This is very long header\r\n"
353 " which should span to more lines.\r\n"
354 " Surrounding LWS are meaning-less. ");
356 http_send_response_403(client_socket
);
359 http_send_response_500(client_socket
,
360 "Could not verify OTP authentication");
365 /* Process OTP session cookie invalidation request */
366 static void do_as_logout(int client_socket
, const struct http_request
*request
,
367 const struct arguments_otp_authentication
*arguments
) {
368 if (arguments
== NULL
) {
369 http_send_response_500(client_socket
,
370 "Third argument of do_as_logout() is NULL");
374 if (request
->method
!= HTTP_METHOD_GET
) {
375 http_send_response_400(client_socket
,
376 "OTP cookie invalidation request must be GET");
380 const char *received_cookie
=
381 http_find_cookie(request
, authorization_cookie_name
);
383 if (authorization_cookie_value
== NULL
|| received_cookie
== NULL
||
384 strcmp(authorization_cookie_value
, received_cookie
)) {
385 http_send_response_403(client_socket
);
389 /* XXX: Add Path parameter to cookie, otherwise
390 * different paths will not match.
391 * FIXME: Domain argument does not work with cURL. Report a bug. */
392 http_send_response_200_cookie(client_socket
,
393 authorization_cookie_name
,
395 /*http_find_host(request)*/ NULL
,
401 /* Process ISDS WS ping authorized by cookie */
402 static void do_ws_with_cookie(int client_socket
, const struct http_request
*request
,
403 const struct arguments_otp_authentication
*arguments
) {
404 const char *received_cookie
=
405 http_find_cookie(request
, authorization_cookie_name
);
407 if (authorization_cookie_value
!= NULL
&& received_cookie
!= NULL
&&
408 !strcmp(authorization_cookie_value
, received_cookie
))
409 do_ws(client_socket
, request
);
411 http_send_response_403(client_socket
);
415 /* Do the server protocol with OTP authentication.
416 * @server_socket is listening TCP socket of the server
417 * @server_arguments is pointer to structure arguments_otp_authentication. It
418 * selects OTP method to enable.
419 * Never returns. Terminates by exit(). */
420 void server_otp_authentication(int server_socket
,
421 const void *server_arguments
) {
423 const struct arguments_otp_authentication
*arguments
=
424 (const struct arguments_otp_authentication
*) server_arguments
;
425 struct http_request
*request
= NULL
;
428 if (arguments
== NULL
) {
429 close(server_socket
);
433 while (0 <= (client_socket
= accept(server_socket
, NULL
, NULL
))) {
434 fprintf(stderr
, "Connection accepted\n");
435 error
= http_read_request(client_socket
, &request
);
437 fprintf(stderr
, "Error while reading request\n");
438 if (error
== HTTP_ERROR_CLIENT
)
439 http_send_response_400(client_socket
, "Error in request");
441 http_send_response_500(client_socket
, "Could not read request");
442 close(client_socket
);
446 if (arguments
->username
!= NULL
) {
447 if (arguments
->method
== AUTH_OTP_HMAC
&&
448 !strncmp(request
->uri
, as_path_hotp
, strlen(as_path_hotp
))) {
449 do_as_phase_two(client_socket
, request
, arguments
);
450 } else if (arguments
->method
== AUTH_OTP_TIME
&&
451 !strncmp(request
->uri
, as_path_sendsms
,
452 strlen(as_path_sendsms
))) {
453 do_as_sendsms(client_socket
, request
, arguments
);
454 } else if (arguments
->method
== AUTH_OTP_TIME
&&
455 !strncmp(request
->uri
, as_path_dontsendsms
,
456 strlen(as_path_dontsendsms
))) {
457 do_as_phase_two(client_socket
, request
, arguments
);
458 } else if (!strncmp(request
->uri
, as_path_logout
,
459 strlen(as_path_logout
))) {
460 do_as_logout(client_socket
, request
, arguments
);
461 } else if (!strcmp(request
->uri
, ws_path
)) {
462 do_ws_with_cookie(client_socket
, request
, arguments
);
464 http_send_response_400(client_socket
,
465 "Unknown path for TOTP authenticating service");
468 if (!strcmp(request
->uri
, ws_path
)) {
469 do_ws(client_socket
, request
);
471 http_send_response_400(client_socket
,
472 "Unknown path for TOTP authenticating service");
475 http_request_free(&request
);
478 close(client_socket
);
481 close(server_socket
);
482 free(authorization_cookie_value
);
487 /* Implementation of server that is out of order.
488 * It always sends back SOAP Fault with HTTP error 503.
489 * @server_socket is listening TCP socket of the server
490 * @server_arguments is ununsed pointer
491 * Never returns. Terminates by exit(). */
492 void server_out_of_order(int server_socket
,
493 const void *server_arguments
) {
495 struct http_request
*request
= NULL
;
497 const char *soap_mime_type
= "text/xml"; /* SOAP/1.1 requires text/xml */
498 const char *fault
= "<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode xsi:type=\"xsd:string\">Probíhá plánovaná údržba</faultcode><faultstring xsi:type=\"xsd:string\">Omlouváme se všem uživatelům datových schránek za dočasné omezení přístupu do systému datových schránek z důvodu plánované údržby systému. Děkujeme za pochopení.</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>";
500 while (0 <= (client_socket
= accept(server_socket
, NULL
, NULL
))) {
501 fprintf(stderr
, "Connection accepted\n");
502 error
= http_read_request(client_socket
, &request
);
504 fprintf(stderr
, "Error while reading request\n");
505 if (error
== HTTP_ERROR_CLIENT
)
506 http_send_response_400(client_socket
, "Error in request");
507 close(client_socket
);
511 http_send_response_503(client_socket
, fault
, strlen(fault
),
513 http_request_free(&request
);
515 close(client_socket
);
518 close(server_socket
);
523 /* Start sever in separate process.
524 * @server_process is PID of forked server
525 * @server_address is automatically allocated TCP address of listening server
526 * @username sets required user name server has to require. Set NULL to
527 * disable HTTP authentication.
528 * @password sets required password server has to require
530 * @isds_deviations is flag to set conformance level. If false, server is
531 * compliant to standards (HTTP, SOAP) if not conflicts with ISDS
532 * specification. Otherwise server mimics real ISDS implementation as much
534 * @return -1 in case of error. */
535 int start_server(pid_t
*server_process
, char **server_address
,
536 void (*server_implementation
)(int, const void *),
537 const void *server_arguments
) {
540 if (server_address
== NULL
) {
541 set_server_error("start_server(): Got invalid server_address pointer");
544 *server_address
= NULL
;
546 if (server_process
== NULL
) {
547 set_server_error("start_server(): Got invalid server_process pointer");
551 server_socket
= listen_on_socket();
552 if (server_socket
== -1) {
553 set_server_error("Could not create listening socket");
557 *server_address
= socket2address(server_socket
);
558 if (*server_address
== NULL
) {
559 close(server_socket
);
560 set_server_error("Could not format address of listening address");
564 *server_process
= fork();
565 if (*server_process
== -1) {
566 close(server_socket
);
567 set_server_error("Server could not been forked");
571 if (*server_process
== 0) {
572 server_implementation(server_socket
, server_arguments
);
573 /* Does not return */
580 /* Kill the server process.
581 * Return -1 in case of error. */
582 int stop_server(pid_t server_process
) {
583 if (server_process
<= 0) {
584 set_server_error("Invalid server PID to kill");
587 if (-1 == kill(server_process
, SIGTERM
)) {
588 set_server_error("Could not terminate server");
591 if (-1 == waitpid(server_process
, NULL
, 0)) {
592 set_server_error("Could not wait for server termination");