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#include <wtf/PassOwnPtr.h>
31
32using namespace EWK2UnitTest;
33
34extern EWK2UnitTestEnvironment* environment;
35
36static const char testUsername[] = "username";
37static const char testPassword[] = "password";
38static const char expectedSuccessTitle[] = "EFLWebKit2 Authentication test";
39static const char expectedAuthorization[] = "Basic dXNlcm5hbWU6cGFzc3dvcmQ="; // Base64 encoding of "username:password".
40static const char indexHTMLString[] =
41    "<html>"
42    "<head><title>EFLWebKit2 Authentication test</title></head>"
43    "<body></body></html>";
44
45static void serverCallback(SoupServer*, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, void*)
46{
47    if (message->method != SOUP_METHOD_GET) {
48        soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
49        return;
50    }
51
52    if (!strcmp(path, "/index.html")) {
53        const char* authorization = soup_message_headers_get_one(message->request_headers, "Authorization");
54        // Require authentication
55        if (authorization && !strcmp(authorization, expectedAuthorization)) {
56            // Successful authentication.
57            soup_message_set_status(message, SOUP_STATUS_OK);
58            soup_message_body_append(message->response_body, SOUP_MEMORY_COPY, indexHTMLString, strlen(indexHTMLString));
59        } else {
60            // No (valid) authorization header provided by the client, request authentication.
61            soup_message_set_status(message, SOUP_STATUS_UNAUTHORIZED);
62            soup_message_headers_append(message->response_headers, "WWW-Authenticate", "Basic realm=\"my realm\"");
63        }
64    } else
65        soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
66
67    soup_message_body_complete(message->response_body);
68}
69
70static void onAuthenticationRequest(void* userData, Evas_Object*, void* eventInfo)
71{
72    Ewk_Auth_Request** returnRequest = static_cast<Ewk_Auth_Request**>(userData);
73    ASSERT_TRUE(returnRequest);
74
75    Ewk_Auth_Request* request = static_cast<Ewk_Auth_Request*>(eventInfo);
76    ASSERT_TRUE(request);
77
78    *returnRequest = ewk_object_ref(request);
79}
80
81TEST_F(EWK2UnitTestBase, ewk_auth_request_success)
82{
83    OwnPtr<EWK2UnitTestServer> httpServer = adoptPtr(new EWK2UnitTestServer);
84    httpServer->run(serverCallback);
85
86    Ewk_Auth_Request* authenticationRequest = 0;
87    evas_object_smart_callback_add(webView(), "authentication,request", onAuthenticationRequest, &authenticationRequest);
88
89    ewk_view_url_set(webView(), httpServer->getURLForPath("/index.html").data());
90
91    while (!authenticationRequest)
92        ecore_main_loop_iterate();
93
94    ASSERT_TRUE(authenticationRequest);
95    evas_object_smart_callback_del(webView(), "authentication,request", onAuthenticationRequest);
96
97    EXPECT_STREQ("my realm", ewk_auth_request_realm_get(authenticationRequest));
98    EXPECT_STREQ("127.0.0.1", ewk_auth_request_host_get(authenticationRequest));
99    EXPECT_FALSE(ewk_auth_request_retrying_get(authenticationRequest));
100
101    ASSERT_TRUE(ewk_auth_request_authenticate(authenticationRequest, testUsername, testPassword));
102
103    ewk_object_unref(authenticationRequest);
104
105    ASSERT_TRUE(waitUntilTitleChangedTo(expectedSuccessTitle));
106}
107
108TEST_F(EWK2UnitTestBase, ewk_auth_request_failure_then_success)
109{
110    OwnPtr<EWK2UnitTestServer> httpServer = adoptPtr(new EWK2UnitTestServer);
111    httpServer->run(serverCallback);
112
113    Ewk_Auth_Request* authenticationRequest = 0;
114    evas_object_smart_callback_add(webView(), "authentication,request", onAuthenticationRequest, &authenticationRequest);
115
116    ewk_view_url_set(webView(), httpServer->getURLForPath("/index.html").data());
117
118    while (!authenticationRequest)
119        ecore_main_loop_iterate();
120
121    ASSERT_TRUE(authenticationRequest);
122
123    EXPECT_STREQ("my realm", ewk_auth_request_realm_get(authenticationRequest));
124    EXPECT_STREQ("127.0.0.1", ewk_auth_request_host_get(authenticationRequest));
125    EXPECT_FALSE(ewk_auth_request_retrying_get(authenticationRequest));
126
127    ASSERT_TRUE(ewk_auth_request_authenticate(authenticationRequest, testUsername, "wrongpassword"));
128
129    ewk_object_unref(authenticationRequest);
130    authenticationRequest = 0;
131
132    // We expect a second authentication request since the first one failed.
133    while (!authenticationRequest)
134        ecore_main_loop_iterate();
135    evas_object_smart_callback_del(webView(), "authentication,request", onAuthenticationRequest);
136
137    EXPECT_STREQ("my realm", ewk_auth_request_realm_get(authenticationRequest));
138    EXPECT_STREQ("127.0.0.1", ewk_auth_request_host_get(authenticationRequest));
139    EXPECT_TRUE(ewk_auth_request_retrying_get(authenticationRequest));
140
141    // Now provide the right password.
142    ASSERT_TRUE(ewk_auth_request_authenticate(authenticationRequest, testUsername, testPassword));
143
144    ewk_object_unref(authenticationRequest);
145
146    ASSERT_TRUE(waitUntilTitleChangedTo(expectedSuccessTitle));
147}
148
149static void onLoadFinished(void* userData, Evas_Object*, void*)
150{
151    bool* isFinished = static_cast<bool*>(userData);
152    ASSERT_TRUE(isFinished);
153
154    *isFinished = true;
155}
156
157TEST_F(EWK2UnitTestBase, ewk_auth_request_cancel)
158{
159    OwnPtr<EWK2UnitTestServer> httpServer = adoptPtr(new EWK2UnitTestServer);
160    httpServer->run(serverCallback);
161
162    Ewk_Auth_Request* authenticationRequest = 0;
163    evas_object_smart_callback_add(webView(), "authentication,request", onAuthenticationRequest, &authenticationRequest);
164
165    ewk_view_url_set(webView(), httpServer->getURLForPath("/index.html").data());
166
167    while (!authenticationRequest)
168        ecore_main_loop_iterate();
169
170    ASSERT_TRUE(authenticationRequest);
171    evas_object_smart_callback_del(webView(), "authentication,request", onAuthenticationRequest);
172
173    EXPECT_STREQ("my realm", ewk_auth_request_realm_get(authenticationRequest));
174    EXPECT_STREQ("127.0.0.1", ewk_auth_request_host_get(authenticationRequest));
175    EXPECT_FALSE(ewk_auth_request_retrying_get(authenticationRequest));
176
177    bool isFinished = false;
178    evas_object_smart_callback_add(webView(), "load,finished", onLoadFinished, &isFinished);
179
180    // Will attempt to continue without authentication by default.
181    ewk_object_unref(authenticationRequest);
182
183    while (!isFinished)
184        ecore_main_loop_iterate();
185
186    ASSERT_STRNE(expectedSuccessTitle, ewk_view_title_get(webView()));
187
188    evas_object_smart_callback_del(webView(), "load,finished", onLoadFinished);
189}
190