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 *ws_base_path_basic
= "/";
33 static const char *ws_base_path_otp
= "/apps/";
35 static const char *authorization_cookie_name
= "IPCZ-X-COOKIE";
36 static char *authorization_cookie_value
= NULL
;
38 /* Save pointer to static error message if not yet set */
39 void set_server_error(const char *message
) {
40 if (server_error
== NULL
) {
41 server_error
= message
;
46 /* Creates listening TCP socket on localhost.
47 * Returns the socket descriptor or -1. */
48 int listen_on_socket(void) {
50 struct addrinfo hints
;
51 struct addrinfo
*addresses
, *address
;
54 memset(&hints
, 0, sizeof(hints
));
55 hints
.ai_family
= AF_UNSPEC
;
56 hints
.ai_socktype
= SOCK_STREAM
;
57 retval
= getaddrinfo("localhost", NULL
, &hints
, &addresses
);
59 set_server_error("Could not resolve `localhost'");
63 for (address
= addresses
; address
!= NULL
; address
= address
->ai_next
) {
64 fd
= socket(address
->ai_family
, address
->ai_socktype
,
65 address
->ai_protocol
);
66 if (fd
== -1) continue;
68 retval
= bind(fd
, address
->ai_addr
, address
->ai_addrlen
);
69 if (retval
!= 0) continue;
71 retval
= listen(fd
, 0);
73 freeaddrinfo(addresses
);
78 freeaddrinfo(addresses
);
79 set_server_error("Could not start listening on TCP/localhost");
84 /* Format socket address as printable string.
85 * @return allocated string or NULL in case of error. */
86 char *socket2address(int socket
) {
87 struct sockaddr_storage storage
;
88 socklen_t length
= (socklen_t
) sizeof(storage
);
89 char host
[NI_MAXHOST
];
90 char service
[NI_MAXSERV
];
93 if (-1 == getsockname(socket
, (struct sockaddr
*)&storage
, &length
)) {
94 set_server_error("Could not get address of server socket");
98 if (0 != getnameinfo((struct sockaddr
*)&storage
, length
,
99 host
, sizeof(host
), service
, sizeof(service
),
100 NI_NUMERICHOST
|NI_NUMERICSERV
)) {
101 set_server_error("Could not resolve address of server socket");
105 if (-1 == test_asprintf(&address
,
106 (strchr(host
, ':') == NULL
) ? "%s:%s" : "[%s]:%s",
108 set_server_error("Could not format server address");
116 /* Process ISDS WS ping */
117 static void do_ws(int client_socket
, const struct http_request
*request
,
118 const char *required_base_path
) {
119 char *end_point
= request
->uri
; /* Pointer to string in request */
121 if (request
->method
!= HTTP_METHOD_POST
) {
122 http_send_response_400(client_socket
,
123 "Regular ISDS web service request must be POST");
127 if (required_base_path
!= NULL
) {
128 size_t required_base_path_length
= strlen(required_base_path
);
129 if (strncmp(end_point
, required_base_path
, required_base_path_length
)) {
130 http_send_response_400(client_socket
,
131 "Request sent to invalid path");
134 end_point
+= required_base_path_length
;
137 soap(client_socket
, request
->body
, request
->body_length
, end_point
);
141 /* Do the server protocol.
142 * @server_socket is listening TCP socket of the server
143 * @server_arguments is pointer to structure:
144 * Never returns. Terminates by exit(). */
145 void server_basic_authentication(int server_socket
,
146 const void *server_arguments
) {
148 const struct arguments_basic_authentication
*arguments
=
149 (const struct arguments_basic_authentication
*) server_arguments
;
150 struct http_request
*request
= NULL
;
153 if (arguments
== NULL
) {
154 close(server_socket
);
158 while (0 <= (client_socket
= accept(server_socket
, NULL
, NULL
))) {
159 fprintf(stderr
, "Connection accepted\n");
160 error
= http_read_request(client_socket
, &request
);
162 fprintf(stderr
, "Error while reading request\n");
163 if (error
== HTTP_ERROR_CLIENT
)
164 http_send_response_400(client_socket
, "Error in request");
166 http_send_response_500(client_socket
,
167 "Error while reading request");
168 close(client_socket
);
172 if (request
->method
== HTTP_METHOD_POST
) {
173 /* Only POST requests are used in Basic authentication mode */
174 if (arguments
->username
!= NULL
) {
175 if (http_client_authenticates(request
)) {
176 switch(http_authenticate_basic(request
,
177 arguments
->username
, arguments
->password
)) {
178 case HTTP_ERROR_SUCCESS
:
179 do_ws(client_socket
, request
, ws_base_path_basic
);
181 case HTTP_ERROR_CLIENT
:
182 if (arguments
->isds_deviations
)
183 http_send_response_401_basic(client_socket
);
185 http_send_response_403(client_socket
);
188 http_send_response_500(client_socket
,
189 "Server error while verifying Basic "
193 http_send_response_401_basic(client_socket
);
196 do_ws(client_socket
, request
, ws_base_path_basic
);
199 /* HTTP method unsupported per ISDS specification */
200 http_send_response_400(client_socket
,
201 "Only POST method is allowed");
203 http_request_free(&request
);
206 close(client_socket
);
209 close(server_socket
);
214 /* Process first phase of TOTP request */
215 static void do_as_sendsms(int client_socket
, const struct http_request
*request
,
216 const struct arguments_otp_authentication
*arguments
) {
217 if (arguments
== NULL
) {
218 http_send_response_500(client_socket
,
219 "Third argument of do_as_sendsms() is NULL");
223 if (request
->method
!= HTTP_METHOD_POST
) {
224 http_send_response_400(client_socket
,
225 "First phase TOTP request must be POST");
229 if (!http_client_authenticates(request
)) {
230 http_send_response_401_otp(client_socket
,
232 "authentication.error.userIsNotAuthenticated",
233 "Client did not send any authentication header");
237 switch(http_authenticate_basic(request
,
238 arguments
->username
, arguments
->password
)) {
239 case HTTP_ERROR_SUCCESS
: {
241 char *uri
= strstr(request
->uri
, "&uri=");
243 http_send_response_400(client_socket
,
244 "Missing uri parameter in Request URI");
248 /* Build new location for second OTP phase */
249 char *location
= NULL
;
250 if (-1 == test_asprintf(&location
, "%s%s", as_path_dontsendsms
, uri
)) {
251 http_send_response_500(client_socket
,
252 "Could not build new localtion for "
256 char *terminator
= strchr(uri
, '&');
257 if (NULL
!= terminator
)
258 location
[strlen(as_path_dontsendsms
) + (uri
- terminator
)] = '\0';
259 http_send_response_302_totp(client_socket
,
260 "authentication.info.totpSended",
261 "=?UTF-8?B?SmVkbm9yw6F6b3bDvSBrw7NkIG9kZXNsw6FuLg==?=",
266 case HTTP_ERROR_CLIENT
:
267 if (arguments
->isds_deviations
)
268 http_send_response_401_otp(client_socket
,
270 "authentication.error.userIsNotAuthenticated",
271 " Retry: Bad user name or password in first OTP phase.\r\n"
272 " This is very long header\r\n"
273 " which should span to more lines.\r\n"
274 " Surrounding LWS are meaning-less. ");
276 http_send_response_403(client_socket
);
279 http_send_response_500(client_socket
,
280 "Could not verify Basic authentication");
285 /* Return static string representation of HTTP OTP authentication method.
286 * Or NULL in case of error. */
287 static const char *auth_otp_method2string(enum auth_otp_method method
) {
289 case AUTH_OTP_HMAC
: return "hotp";
290 case AUTH_OTP_TIME
: return "totp";
291 default: return NULL
;
296 /* Process second phase of OTP request */
297 static void do_as_phase_two(int client_socket
, const struct http_request
*request
,
298 const struct arguments_otp_authentication
*arguments
) {
299 if (arguments
== NULL
) {
300 http_send_response_500(client_socket
,
301 "Third argument of do_as_phase_two() is NULL");
305 if (request
->method
!= HTTP_METHOD_POST
) {
306 http_send_response_400(client_socket
,
307 "Second phase OTP request must be POST");
311 if (!http_client_authenticates(request
)) {
312 http_send_response_401_otp(client_socket
,
313 auth_otp_method2string(arguments
->method
),
314 "authentication.error.userIsNotAuthenticated",
315 "Client did not send any authentication header");
319 switch(http_authenticate_otp(request
,
320 arguments
->username
, arguments
->password
, arguments
->otp
)) {
321 case HTTP_ERROR_SUCCESS
: {
323 char *uri
= strstr(request
->uri
, "&uri=");
325 http_send_response_400(client_socket
,
326 "Missing uri parameter in Request URI");
330 /* Build new location for final request */
331 char *location
= NULL
;
332 if (NULL
== (location
= strdup(uri
))) {
333 http_send_response_500(client_socket
,
334 "Could not build new location for final request");
337 char *terminator
= strchr(location
, '&');
338 if (NULL
!= terminator
)
340 /* Generate pseudo-random cookie value. This is to prevent
341 * client from reusing the cookie accidentally. We use the
342 * same seed to get reproducible tests. */
343 if (-1 == test_asprintf(&authorization_cookie_value
, "%d",
345 http_send_response_500(client_socket
,
346 "Could not generate cookie value");
350 /* XXX: Add Path parameter to cookie, otherwise
351 * different paths will not match.
352 * FIXME: Domain argument does not work with cURL. Report a bug. */
353 http_send_response_302_cookie(client_socket
,
354 authorization_cookie_name
,
355 authorization_cookie_value
,
356 /*http_find_host(request)*/NULL
,
362 case HTTP_ERROR_CLIENT
:
363 if (arguments
->isds_deviations
)
364 http_send_response_401_otp(client_socket
,
365 auth_otp_method2string(arguments
->method
),
366 "authentication.error.userIsNotAuthenticated",
367 " Retry: Bad user name or password in second OTP phase.\r\n"
368 " This is very long header\r\n"
369 " which should span to more lines.\r\n"
370 " Surrounding LWS are meaning-less. ");
372 http_send_response_403(client_socket
);
375 http_send_response_500(client_socket
,
376 "Could not verify OTP authentication");
381 /* Process OTP session cookie invalidation request */
382 static void do_as_logout(int client_socket
, const struct http_request
*request
,
383 const struct arguments_otp_authentication
*arguments
) {
384 if (arguments
== NULL
) {
385 http_send_response_500(client_socket
,
386 "Third argument of do_as_logout() is NULL");
390 if (request
->method
!= HTTP_METHOD_GET
) {
391 http_send_response_400(client_socket
,
392 "OTP cookie invalidation request must be GET");
396 const char *received_cookie
=
397 http_find_cookie(request
, authorization_cookie_name
);
399 if (authorization_cookie_value
== NULL
|| received_cookie
== NULL
||
400 strcmp(authorization_cookie_value
, received_cookie
)) {
401 http_send_response_403(client_socket
);
405 /* XXX: Add Path parameter to cookie, otherwise
406 * different paths will not match.
407 * FIXME: Domain argument does not work with cURL. Report a bug. */
408 http_send_response_200_cookie(client_socket
,
409 authorization_cookie_name
,
411 /*http_find_host(request)*/ NULL
,
417 /* Process ISDS WS ping authorized by cookie */
418 static void do_ws_with_cookie(int client_socket
, const struct http_request
*request
,
419 const struct arguments_otp_authentication
*arguments
,
420 const char *valid_base_path
) {
421 const char *received_cookie
=
422 http_find_cookie(request
, authorization_cookie_name
);
424 if (authorization_cookie_value
!= NULL
&& received_cookie
!= NULL
&&
425 !strcmp(authorization_cookie_value
, received_cookie
))
426 do_ws(client_socket
, request
, valid_base_path
);
428 http_send_response_403(client_socket
);
432 /* Do the server protocol with OTP authentication.
433 * @server_socket is listening TCP socket of the server
434 * @server_arguments is pointer to structure arguments_otp_authentication. It
435 * selects OTP method to enable.
436 * Never returns. Terminates by exit(). */
437 void server_otp_authentication(int server_socket
,
438 const void *server_arguments
) {
440 const struct arguments_otp_authentication
*arguments
=
441 (const struct arguments_otp_authentication
*) server_arguments
;
442 struct http_request
*request
= NULL
;
445 if (arguments
== NULL
) {
446 close(server_socket
);
450 while (0 <= (client_socket
= accept(server_socket
, NULL
, NULL
))) {
451 fprintf(stderr
, "Connection accepted\n");
452 error
= http_read_request(client_socket
, &request
);
454 fprintf(stderr
, "Error while reading request\n");
455 if (error
== HTTP_ERROR_CLIENT
)
456 http_send_response_400(client_socket
, "Error in request");
458 http_send_response_500(client_socket
, "Could not read request");
459 close(client_socket
);
463 if (arguments
->username
!= NULL
) {
464 if (arguments
->method
== AUTH_OTP_HMAC
&&
465 !strncmp(request
->uri
, as_path_hotp
, strlen(as_path_hotp
))) {
466 do_as_phase_two(client_socket
, request
, arguments
);
467 } else if (arguments
->method
== AUTH_OTP_TIME
&&
468 !strncmp(request
->uri
, as_path_sendsms
,
469 strlen(as_path_sendsms
))) {
470 do_as_sendsms(client_socket
, request
, arguments
);
471 } else if (arguments
->method
== AUTH_OTP_TIME
&&
472 !strncmp(request
->uri
, as_path_dontsendsms
,
473 strlen(as_path_dontsendsms
))) {
474 do_as_phase_two(client_socket
, request
, arguments
);
475 } else if (!strncmp(request
->uri
, as_path_logout
,
476 strlen(as_path_logout
))) {
477 do_as_logout(client_socket
, request
, arguments
);
478 } else if (!strcmp(request
->uri
, ws_path
)) {
479 do_ws_with_cookie(client_socket
, request
, arguments
,
482 http_send_response_400(client_socket
,
483 "Unknown path for TOTP authenticating service");
486 if (!strcmp(request
->uri
, ws_path
)) {
487 do_ws(client_socket
, request
, ws_base_path_otp
);
489 http_send_response_400(client_socket
,
490 "Unknown path for TOTP authenticating service");
493 http_request_free(&request
);
496 close(client_socket
);
499 close(server_socket
);
500 free(authorization_cookie_value
);
505 /* Implementation of server that is out of order.
506 * It always sends back SOAP Fault with HTTP error 503.
507 * @server_socket is listening TCP socket of the server
508 * @server_arguments is ununsed pointer
509 * Never returns. Terminates by exit(). */
510 void server_out_of_order(int server_socket
,
511 const void *server_arguments
) {
513 struct http_request
*request
= NULL
;
515 const char *soap_mime_type
= "text/xml"; /* SOAP/1.1 requires text/xml */
516 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>";
518 while (0 <= (client_socket
= accept(server_socket
, NULL
, NULL
))) {
519 fprintf(stderr
, "Connection accepted\n");
520 error
= http_read_request(client_socket
, &request
);
522 fprintf(stderr
, "Error while reading request\n");
523 if (error
== HTTP_ERROR_CLIENT
)
524 http_send_response_400(client_socket
, "Error in request");
525 close(client_socket
);
529 http_send_response_503(client_socket
, fault
, strlen(fault
),
531 http_request_free(&request
);
533 close(client_socket
);
536 close(server_socket
);
541 /* Start sever in separate process.
542 * @server_process is PID of forked server
543 * @server_address is automatically allocated TCP address of listening server
544 * @username sets required user name server has to require. Set NULL to
545 * disable HTTP authentication.
546 * @password sets required password server has to require
548 * @isds_deviations is flag to set conformance level. If false, server is
549 * compliant to standards (HTTP, SOAP) if not conflicts with ISDS
550 * specification. Otherwise server mimics real ISDS implementation as much
552 * @return -1 in case of error. */
553 int start_server(pid_t
*server_process
, char **server_address
,
554 void (*server_implementation
)(int, const void *),
555 const void *server_arguments
) {
558 if (server_address
== NULL
) {
559 set_server_error("start_server(): Got invalid server_address pointer");
562 *server_address
= NULL
;
564 if (server_process
== NULL
) {
565 set_server_error("start_server(): Got invalid server_process pointer");
569 server_socket
= listen_on_socket();
570 if (server_socket
== -1) {
571 set_server_error("Could not create listening socket");
575 *server_address
= socket2address(server_socket
);
576 if (*server_address
== NULL
) {
577 close(server_socket
);
578 set_server_error("Could not format address of listening address");
582 *server_process
= fork();
583 if (*server_process
== -1) {
584 close(server_socket
);
585 set_server_error("Server could not been forked");
589 if (*server_process
== 0) {
590 server_implementation(server_socket
, server_arguments
);
591 /* Does not return */
598 /* Kill the server process.
599 * Return -1 in case of error. */
600 int stop_server(pid_t server_process
) {
601 if (server_process
<= 0) {
602 set_server_error("Invalid server PID to kill");
605 if (-1 == kill(server_process
, SIGTERM
)) {
606 set_server_error("Could not terminate server");
609 if (-1 == waitpid(server_process
, NULL
, 0)) {
610 set_server_error("Could not wait for server termination");