1/* 2 * Copyright (C) 2012 Research In Motion Limited. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20#include "AuthenticationChallengeManager.h" 21 22#include "Credential.h" 23#include "KURL.h" 24#include "PageClientBlackBerry.h" 25#include "ProtectionSpace.h" 26 27#include <BlackBerryPlatformAssert.h> 28#include <BlackBerryPlatformLog.h> 29#include <wtf/Assertions.h> 30#include <wtf/HashMap.h> 31#include <wtf/PassOwnPtr.h> 32#include <wtf/Vector.h> 33#include <wtf/text/CString.h> 34 35namespace WebCore { 36 37typedef HashMap<PageClientBlackBerry*, bool> PageVisibilityMap; 38 39struct ChallengeInfo { 40 ChallengeInfo(const KURL&, const ProtectionSpace&, const Credential&, AuthenticationChallengeClient*, PageClientBlackBerry*); 41 42 KURL url; 43 ProtectionSpace space; 44 Credential credential; 45 AuthenticationChallengeClient* authClient; 46 PageClientBlackBerry* pageClient; 47 bool blocked; 48}; 49 50ChallengeInfo::ChallengeInfo(const KURL& aUrl, const ProtectionSpace& aSpace, const Credential& aCredential, 51 AuthenticationChallengeClient* anAuthClient, PageClientBlackBerry* aPageClient) 52 : url(aUrl) 53 , space(aSpace) 54 , credential(aCredential) 55 , authClient(anAuthClient) 56 , pageClient(aPageClient) 57 , blocked(false) 58{ 59} 60 61class AuthenticationChallengeManagerPrivate { 62public: 63 AuthenticationChallengeManagerPrivate(); 64 65 bool resumeAuthenticationChallenge(PageClientBlackBerry*); 66 void startAuthenticationChallenge(ChallengeInfo*); 67 bool pageExists(PageClientBlackBerry*); 68 69 ChallengeInfo* m_activeChallenge; 70 PageVisibilityMap m_pageVisibilityMap; 71 Vector<OwnPtr<ChallengeInfo> > m_challenges; 72}; 73 74AuthenticationChallengeManagerPrivate::AuthenticationChallengeManagerPrivate() 75 : m_activeChallenge(0) 76{ 77} 78 79bool AuthenticationChallengeManagerPrivate::resumeAuthenticationChallenge(PageClientBlackBerry* client) 80{ 81 ASSERT(!m_activeChallenge); 82 83 for (size_t i = 0; i < m_challenges.size(); ++i) { 84 if (m_challenges[i]->pageClient == client && m_challenges[i]->blocked) { 85 startAuthenticationChallenge(m_challenges[i].get()); 86 return true; 87 } 88 } 89 90 return false; 91} 92 93void AuthenticationChallengeManagerPrivate::startAuthenticationChallenge(ChallengeInfo* info) 94{ 95 m_activeChallenge = info; 96 m_activeChallenge->blocked = false; 97 m_activeChallenge->pageClient->authenticationChallenge(m_activeChallenge->url, m_activeChallenge->space, m_activeChallenge->credential); 98} 99 100bool AuthenticationChallengeManagerPrivate::pageExists(PageClientBlackBerry* client) 101{ 102 return m_pageVisibilityMap.find(client) != m_pageVisibilityMap.end(); 103} 104 105SINGLETON_INITIALIZER_THREADUNSAFE(AuthenticationChallengeManager) 106 107AuthenticationChallengeManager::AuthenticationChallengeManager() 108 : d(adoptPtr(new AuthenticationChallengeManagerPrivate)) 109{ 110} 111 112void AuthenticationChallengeManager::pageCreated(PageClientBlackBerry* client) 113{ 114 d->m_pageVisibilityMap.add(client, true); 115} 116 117void AuthenticationChallengeManager::pageDeleted(PageClientBlackBerry* client) 118{ 119 d->m_pageVisibilityMap.remove(client); 120 121 if (d->m_activeChallenge && d->m_activeChallenge->pageClient == client) 122 d->m_activeChallenge = 0; 123 124 Vector<OwnPtr<ChallengeInfo> > existing; 125 d->m_challenges.swap(existing); 126 127 for (size_t i = 0; i < existing.size(); ++i) { 128 if (existing[i]->pageClient != client) 129 d->m_challenges.append(existing[i].release()); 130 } 131} 132 133void AuthenticationChallengeManager::pageVisibilityChanged(PageClientBlackBerry* client, bool visible) 134{ 135 PageVisibilityMap::iterator iter = d->m_pageVisibilityMap.find(client); 136 137 ASSERT(iter != d->m_pageVisibilityMap.end()); 138 if (iter == d->m_pageVisibilityMap.end()) { 139 d->m_pageVisibilityMap.add(client, visible); 140 return; 141 } 142 143 if (iter->value == visible) 144 return; 145 146 iter->value = visible; 147 if (!visible) 148 return; 149 150 if (d->m_activeChallenge) 151 return; 152 153 d->resumeAuthenticationChallenge(client); 154} 155 156void AuthenticationChallengeManager::authenticationChallenge(const KURL& url, const ProtectionSpace& space, 157 const Credential& credential, AuthenticationChallengeClient* authClient, PageClientBlackBerry* pageClient) 158{ 159 BLACKBERRY_ASSERT(authClient); 160 BLACKBERRY_ASSERT(pageClient); 161 162 ChallengeInfo* info = new ChallengeInfo(url, space, credential, authClient, pageClient); 163 d->m_challenges.append(adoptPtr(info)); 164 165 if (d->m_activeChallenge || !pageClient->isVisible()) { 166 info->blocked = true; 167 return; 168 } 169 170 d->startAuthenticationChallenge(info); 171} 172 173void AuthenticationChallengeManager::cancelAuthenticationChallenge(AuthenticationChallengeClient* client) 174{ 175 BLACKBERRY_ASSERT(client); 176 177 if (d->m_activeChallenge && d->m_activeChallenge->authClient == client) 178 d->m_activeChallenge = 0; 179 180 Vector<OwnPtr<ChallengeInfo> > existing; 181 d->m_challenges.swap(existing); 182 183 ChallengeInfo* next = 0; 184 PageClientBlackBerry* page = 0; 185 186 for (size_t i = 0; i < existing.size(); ++i) { 187 if (existing[i]->authClient != client) { 188 if (page && !next && existing[i]->pageClient == page) 189 next = existing[i].get(); 190 d->m_challenges.append(existing[i].release()); 191 } else if (d->m_activeChallenge == existing[i].get()) 192 page = existing[i]->pageClient; 193 } 194 195 if (next) 196 d->startAuthenticationChallenge(next); 197} 198 199void AuthenticationChallengeManager::notifyChallengeResult(const KURL&, const ProtectionSpace& space, 200 AuthenticationChallengeResult result, const Credential& credential) 201{ 202 d->m_activeChallenge = 0; 203 204 Vector<OwnPtr<ChallengeInfo> > existing; 205 d->m_challenges.swap(existing); 206 207 ChallengeInfo* next = 0; 208 PageClientBlackBerry* page = 0; 209 210 for (size_t i = 0; i < existing.size(); ++i) { 211 if (existing[i]->space != space) { 212 if (page && !next && existing[i]->pageClient == page) 213 next = existing[i].get(); 214 d->m_challenges.append(existing[i].release()); 215 } else { 216 page = existing[i]->pageClient; 217 existing[i]->authClient->notifyChallengeResult(existing[i]->url, space, result, credential); 218 219 // After calling notifyChallengeResult(), page could be destroyed or something. 220 if (!d->pageExists(page) || !page->isVisible()) 221 page = 0; 222 } 223 } 224 225 if (next) 226 d->startAuthenticationChallenge(next); 227} 228 229} // namespace WebCore 230