1/*
2 * Copyright (C) 2012 Intel Corporation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "UnitTestUtils/EWK2UnitTestBase.h"
29#include "UnitTestUtils/EWK2UnitTestServer.h"
30
31using namespace EWK2UnitTest;
32
33extern EWK2UnitTestEnvironment* environment;
34
35static const char testUsername[] = "username";
36static const char testPassword[] = "password";
37static const char expectedSuccessTitle[] = "EFLWebKit2 Authentication test";
38static const char expectedAuthorization[] = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="; // Base64 encoding of "username:password".
39static const char indexHTMLString[] =
40    "<html>"
41    "<head><title>EFLWebKit2 Authentication test</title></head>"
42    "<body></body></html>";
43
44class EWK2AuthRequestTest : public EWK2UnitTestBase {
45public:
46    static void serverCallback(SoupServer*, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, void*)
47    {
48        if (message->method != SOUP_METHOD_GET) {
49            soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
50            return;
51        }
52
53        if (!strcmp(path, "/index.html")) {
54            const char* authorization = soup_message_headers_get_one(message->request_headers, "Authorization");
55            // Require authentication
56            if (authorization && !strcmp(authorization, expectedAuthorization)) {
57                // Successful authentication.
58                soup_message_set_status(message, SOUP_STATUS_OK);
59                soup_message_body_append(message->response_body, SOUP_MEMORY_COPY, indexHTMLString, strlen(indexHTMLString));
60            } else {
61                // No (valid) authorization header provided by the client, request authentication.
62                soup_message_set_status(message, SOUP_STATUS_UNAUTHORIZED);
63                soup_message_headers_append(message->response_headers, "WWW-Authenticate", "Basic realm=\"my realm\"");
64            }
65        } else
66            soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
67
68        soup_message_body_complete(message->response_body);
69    }
70
71    static void onAuthenticationRequest(void* userData, Evas_Object*, void* eventInfo)
72    {
73        Ewk_Auth_Request** returnRequest = static_cast<Ewk_Auth_Request**>(userData);
74        ASSERT_TRUE(returnRequest);
75
76        Ewk_Auth_Request* request = static_cast<Ewk_Auth_Request*>(eventInfo);
77        ASSERT_TRUE(request);
78
79        *returnRequest = ewk_object_ref(request);
80    }
81
82    static void onLoadFinished(void* userData, Evas_Object*, void*)
83    {
84        bool* isFinished = static_cast<bool*>(userData);
85        ASSERT_TRUE(isFinished);
86
87        *isFinished = true;
88    }
89};
90
91TEST_F(EWK2AuthRequestTest, ewk_auth_request_success)
92{
93    std::unique_ptr<EWK2UnitTestServer> httpServer = std::make_unique<EWK2UnitTestServer>();
94    httpServer->run(serverCallback);
95
96    Ewk_Auth_Request* authenticationRequest = 0;
97    evas_object_smart_callback_add(webView(), "authentication,request", onAuthenticationRequest, &authenticationRequest);
98
99    ewk_view_url_set(webView(), httpServer->getURLForPath("/index.html").data());
100
101    while (!authenticationRequest)
102        ecore_main_loop_iterate();
103
104    ASSERT_TRUE(authenticationRequest);
105    evas_object_smart_callback_del(webView(), "authentication,request", onAuthenticationRequest);
106
107    EXPECT_STREQ("my realm", ewk_auth_request_realm_get(authenticationRequest));
108    EXPECT_STREQ("127.0.0.1", ewk_auth_request_host_get(authenticationRequest));
109    EXPECT_FALSE(ewk_auth_request_retrying_get(authenticationRequest));
110
111    ASSERT_TRUE(ewk_auth_request_authenticate(authenticationRequest, testUsername, testPassword));
112
113    ewk_object_unref(authenticationRequest);
114
115    ASSERT_TRUE(waitUntilTitleChangedTo(expectedSuccessTitle));
116}
117
118TEST_F(EWK2AuthRequestTest, ewk_auth_request_failure_then_success)
119{
120    std::unique_ptr<EWK2UnitTestServer> httpServer = std::make_unique<EWK2UnitTestServer>();
121    httpServer->run(serverCallback);
122
123    Ewk_Auth_Request* authenticationRequest = 0;
124    evas_object_smart_callback_add(webView(), "authentication,request", onAuthenticationRequest, &authenticationRequest);
125
126    ewk_view_url_set(webView(), httpServer->getURLForPath("/index.html").data());
127
128    while (!authenticationRequest)
129        ecore_main_loop_iterate();
130
131    ASSERT_TRUE(authenticationRequest);
132
133    EXPECT_STREQ("my realm", ewk_auth_request_realm_get(authenticationRequest));
134    EXPECT_STREQ("127.0.0.1", ewk_auth_request_host_get(authenticationRequest));
135    EXPECT_FALSE(ewk_auth_request_retrying_get(authenticationRequest));
136
137    ASSERT_TRUE(ewk_auth_request_authenticate(authenticationRequest, testUsername, "wrongpassword"));
138
139    ewk_object_unref(authenticationRequest);
140    authenticationRequest = 0;
141
142    // We expect a second authentication request since the first one failed.
143    while (!authenticationRequest)
144        ecore_main_loop_iterate();
145    evas_object_smart_callback_del(webView(), "authentication,request", onAuthenticationRequest);
146
147    EXPECT_STREQ("my realm", ewk_auth_request_realm_get(authenticationRequest));
148    EXPECT_STREQ("127.0.0.1", ewk_auth_request_host_get(authenticationRequest));
149    EXPECT_TRUE(ewk_auth_request_retrying_get(authenticationRequest));
150
151    // Now provide the right password.
152    ASSERT_TRUE(ewk_auth_request_authenticate(authenticationRequest, testUsername, testPassword));
153
154    ewk_object_unref(authenticationRequest);
155
156    ASSERT_TRUE(waitUntilTitleChangedTo(expectedSuccessTitle));
157}
158
159TEST_F(EWK2AuthRequestTest, ewk_auth_request_cancel)
160{
161    std::unique_ptr<EWK2UnitTestServer> httpServer = std::make_unique<EWK2UnitTestServer>();
162    httpServer->run(serverCallback);
163
164    Ewk_Auth_Request* authenticationRequest = 0;
165    evas_object_smart_callback_add(webView(), "authentication,request", onAuthenticationRequest, &authenticationRequest);
166
167    ewk_view_url_set(webView(), httpServer->getURLForPath("/index.html").data());
168
169    while (!authenticationRequest)
170        ecore_main_loop_iterate();
171
172    ASSERT_TRUE(authenticationRequest);
173    evas_object_smart_callback_del(webView(), "authentication,request", onAuthenticationRequest);
174
175    EXPECT_STREQ("my realm", ewk_auth_request_realm_get(authenticationRequest));
176    EXPECT_STREQ("127.0.0.1", ewk_auth_request_host_get(authenticationRequest));
177    EXPECT_FALSE(ewk_auth_request_retrying_get(authenticationRequest));
178
179    bool isFinished = false;
180    evas_object_smart_callback_add(webView(), "load,finished", onLoadFinished, &isFinished);
181
182    // Will attempt to continue without authentication by default.
183    ewk_object_unref(authenticationRequest);
184
185    waitUntilTrue(isFinished);
186
187    ASSERT_STRNE(expectedSuccessTitle, ewk_view_title_get(webView()));
188
189    evas_object_smart_callback_del(webView(), "load,finished", onLoadFinished);
190}
191