Clean up AuthenticationChallengeProxy
[WebKit-https.git] / Source / WebKit / Shared / Authentication / AuthenticationManager.cpp
1 /*
2  * Copyright (C) 2010, 2013 Apple Inc. 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 #include "AuthenticationManager.h"
28
29 #include "AuthenticationManagerMessages.h"
30 #include "ChildProcess.h"
31 #include "Download.h"
32 #include "DownloadProxyMessages.h"
33 #include "NetworkProcessProxyMessages.h"
34 #include "PendingDownload.h"
35 #include "WebCoreArgumentCoders.h"
36 #include "WebFrame.h"
37 #include "WebPage.h"
38 #include "WebPageProxyMessages.h"
39 #include <WebCore/AuthenticationChallenge.h>
40
41 namespace WebKit {
42 using namespace WebCore;
43
44 static uint64_t generateAuthenticationChallengeID()
45 {
46     ASSERT(RunLoop::isMain());
47
48     static int64_t uniqueAuthenticationChallengeID;
49     return ++uniqueAuthenticationChallengeID;
50 }
51
52 static bool canCoalesceChallenge(const WebCore::AuthenticationChallenge& challenge)
53 {
54     // Do not coalesce server trust evaluation requests because ProtectionSpace comparison does not evaluate server trust (e.g. certificate).
55     return challenge.protectionSpace().authenticationScheme() != ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
56 }
57
58 const char* AuthenticationManager::supplementName()
59 {
60     return "AuthenticationManager";
61 }
62
63 AuthenticationManager::AuthenticationManager(ChildProcess& process)
64     : m_process(process)
65 {
66     m_process.addMessageReceiver(Messages::AuthenticationManager::messageReceiverName(), *this);
67 }
68
69 uint64_t AuthenticationManager::addChallengeToChallengeMap(Challenge&& challenge)
70 {
71     ASSERT(RunLoop::isMain());
72
73     uint64_t challengeID = generateAuthenticationChallengeID();
74     m_challenges.set(challengeID, WTFMove(challenge));
75     return challengeID;
76 }
77
78 bool AuthenticationManager::shouldCoalesceChallenge(uint64_t pageID, uint64_t challengeID, const AuthenticationChallenge& challenge) const
79 {
80     if (!canCoalesceChallenge(challenge))
81         return false;
82
83     for (auto& item : m_challenges) {
84         if (item.key != challengeID && item.value.pageID == pageID && ProtectionSpace::compare(challenge.protectionSpace(), item.value.challenge.protectionSpace()))
85             return true;
86     }
87     return false;
88 }
89
90 Vector<uint64_t> AuthenticationManager::coalesceChallengesMatching(uint64_t challengeID) const
91 {
92     auto iterator = m_challenges.find(challengeID);
93     ASSERT(iterator != m_challenges.end());
94
95     auto& challenge = iterator->value;
96
97     Vector<uint64_t> challengesToCoalesce;
98     challengesToCoalesce.append(challengeID);
99
100     if (!canCoalesceChallenge(challenge.challenge))
101         return challengesToCoalesce;
102
103     for (auto& item : m_challenges) {
104         if (item.key != challengeID && item.value.pageID == challenge.pageID && ProtectionSpace::compare(challenge.challenge.protectionSpace(), item.value.challenge.protectionSpace()))
105             challengesToCoalesce.append(item.key);
106     }
107
108     return challengesToCoalesce;
109 }
110
111 void AuthenticationManager::didReceiveAuthenticationChallenge(uint64_t pageID, uint64_t frameID, const AuthenticationChallenge& authenticationChallenge, ChallengeCompletionHandler&& completionHandler)
112 {
113     ASSERT(pageID);
114     ASSERT(frameID);
115
116     uint64_t challengeID = addChallengeToChallengeMap({ pageID, authenticationChallenge, WTFMove(completionHandler) });
117
118     // Coalesce challenges in the same protection space and in the same page.
119     if (shouldCoalesceChallenge(pageID, challengeID, authenticationChallenge))
120         return;
121     
122     m_process.send(Messages::NetworkProcessProxy::DidReceiveAuthenticationChallenge(pageID, frameID, authenticationChallenge, challengeID));
123 }
124
125 void AuthenticationManager::didReceiveAuthenticationChallenge(IPC::MessageSender& download, const WebCore::AuthenticationChallenge& authenticationChallenge, ChallengeCompletionHandler&& completionHandler)
126 {
127     uint64_t dummyPageID = 0;
128     uint64_t challengeID = addChallengeToChallengeMap({ dummyPageID, authenticationChallenge, WTFMove(completionHandler) });
129     
130     // Coalesce challenges in the same protection space and in the same page.
131     if (shouldCoalesceChallenge(dummyPageID, challengeID, authenticationChallenge))
132         return;
133     
134     download.send(Messages::DownloadProxy::DidReceiveAuthenticationChallenge(authenticationChallenge, challengeID));
135 }
136
137 void AuthenticationManager::useCredentialForChallenge(uint64_t challengeID, const Credential& credential)
138 {
139     ASSERT(RunLoop::isMain());
140
141     for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
142         useCredentialForSingleChallenge(coalescedChallengeID, credential);
143 }
144
145 void AuthenticationManager::useCredentialForSingleChallenge(uint64_t challengeID, const Credential& credential)
146 {
147     auto challenge = m_challenges.take(challengeID);
148     ASSERT(!challenge.challenge.isNull());
149
150     auto completionHandler = WTFMove(challenge.completionHandler);
151
152     if (completionHandler)
153         completionHandler(AuthenticationChallengeDisposition::UseCredential, credential);
154     else
155         ASSERT_NOT_REACHED();
156 }
157
158 void AuthenticationManager::continueWithoutCredentialForChallenge(uint64_t challengeID)
159 {
160     ASSERT(RunLoop::isMain());
161
162     for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
163         continueWithoutCredentialForSingleChallenge(coalescedChallengeID);
164 }
165
166 void AuthenticationManager::continueWithoutCredentialForSingleChallenge(uint64_t challengeID)
167 {
168     auto challenge = m_challenges.take(challengeID);
169     ASSERT(!challenge.challenge.isNull());
170
171     if (challenge.completionHandler)
172         challenge.completionHandler(AuthenticationChallengeDisposition::UseCredential, Credential());
173     else
174         ASSERT_NOT_REACHED();
175 }
176
177 void AuthenticationManager::cancelChallenge(uint64_t challengeID)
178 {
179     ASSERT(RunLoop::isMain());
180
181     for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
182         cancelSingleChallenge(coalescedChallengeID);
183 }
184
185 void AuthenticationManager::cancelSingleChallenge(uint64_t challengeID)
186 {
187     auto challenge = m_challenges.take(challengeID);
188     ASSERT(!challenge.challenge.isNull());
189
190     if (challenge.completionHandler)
191         challenge.completionHandler(AuthenticationChallengeDisposition::Cancel, Credential());
192     else
193         ASSERT_NOT_REACHED();
194 }
195
196 void AuthenticationManager::performDefaultHandling(uint64_t challengeID)
197 {
198     ASSERT(RunLoop::isMain());
199
200     for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
201         performDefaultHandlingForSingleChallenge(coalescedChallengeID);
202 }
203
204 void AuthenticationManager::performDefaultHandlingForSingleChallenge(uint64_t challengeID)
205 {
206     auto challenge = m_challenges.take(challengeID);
207     ASSERT(!challenge.challenge.isNull());
208
209     if (challenge.completionHandler)
210         challenge.completionHandler(AuthenticationChallengeDisposition::PerformDefaultHandling, Credential());
211     else
212         ASSERT_NOT_REACHED();
213 }
214
215 void AuthenticationManager::rejectProtectionSpaceAndContinue(uint64_t challengeID)
216 {
217     ASSERT(RunLoop::isMain());
218
219     for (auto& coalescedChallengeID : coalesceChallengesMatching(challengeID))
220         rejectProtectionSpaceAndContinueForSingleChallenge(coalescedChallengeID);
221 }
222
223 void AuthenticationManager::rejectProtectionSpaceAndContinueForSingleChallenge(uint64_t challengeID)
224 {
225     auto challenge = m_challenges.take(challengeID);
226     ASSERT(!challenge.challenge.isNull());
227
228     if (challenge.completionHandler)
229         challenge.completionHandler(AuthenticationChallengeDisposition::RejectProtectionSpaceAndContinue, { });
230     else
231         ASSERT_NOT_REACHED();
232 }
233
234 } // namespace WebKit