Skip to content

Commit

Permalink
HTTP basic auth support. Fixes #26
Browse files Browse the repository at this point in the history
  • Loading branch information
cretz committed Oct 2, 2017
1 parent cf3e213 commit c870baf
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/browser_widget.cc
Expand Up @@ -395,7 +395,8 @@ void BrowserWidget::RecreateCefWidget(const QString& url,
// as much about the transition type.
// TODO(cretz): Test when title/favicon is not changed or not present
if (!is_loading) {
PageIndex::MarkVisit(CurrentUrl(), current_title_,
auto title = current_title_.isNull() ? "" : current_title_;
PageIndex::MarkVisit(CurrentUrl(), title,
current_favicon_url_, current_favicon_);
}

Expand Down
15 changes: 15 additions & 0 deletions src/cef/cef_handler.cc
Expand Up @@ -248,4 +248,19 @@ bool CefHandler::OnOpenURLFromTab(
return true;
}

bool CefHandler::GetAuthCredentials(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
bool is_proxy,
const CefString& host,
int port,
const CefString& realm,
const CefString& scheme,
CefRefPtr<CefAuthCallback> callback) {
emit AuthRequest(frame, is_proxy,
QString::fromStdString(host.ToString()), port,
QString::fromStdString(realm.ToString()),
QString::fromStdString(scheme.ToString()), callback);
return true;
}

} // namespace doogie
15 changes: 15 additions & 0 deletions src/cef/cef_handler.h
Expand Up @@ -235,6 +235,14 @@ class CefHandler :
const CefString& target_url,
CefRequestHandler::WindowOpenDisposition target_disposition,
bool user_gesture) override;
bool GetAuthCredentials(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
bool is_proxy,
const CefString& host,
int port,
const CefString& realm,
const CefString& scheme,
CefRefPtr<CefAuthCallback> callback) override;

signals:
void PreContextMenu(CefRefPtr<CefContextMenuParams> params,
Expand Down Expand Up @@ -279,6 +287,13 @@ class CefHandler :
CefRefPtr<CefSSLInfo> ssl_info,
CefRefPtr<CefRequestCallback> callback);
void PageOpen(WindowOpenType type, const QString& url, bool user_gesture);
void AuthRequest(CefRefPtr<CefFrame> frame,
bool is_proxy,
const QString& host,
int port,
const QString& realm,
const QString& scheme,
CefRefPtr<CefAuthCallback> callback);
void BrowserLog(const QString& str);

private:
Expand Down
53 changes: 53 additions & 0 deletions src/cef/cef_widget.cc
Expand Up @@ -67,6 +67,12 @@ CefWidget::CefWidget(const Cef& cef,
});
connect(handler_, &CefHandler::ShowBeforeUnloadDialog,
this, &CefWidget::ShowBeforeUnloadDialog);
connect(handler_, &CefHandler::AuthRequest,
[=](CefRefPtr<CefFrame>, bool, const QString&,
int, const QString& realm, const QString&,
CefRefPtr<CefAuthCallback> callback) {
Util::RunOnMainThread([=]() { AuthRequest(realm, callback); });
});

InitBrowser(bubble, url);
}
Expand Down Expand Up @@ -353,4 +359,51 @@ void CefWidget::InitBrowser(const Bubble& bubble, const QString& url) {
bubble.CreateCefRequestContext());
}

void CefWidget::AuthRequest(const QString& realm,
CefRefPtr<CefAuthCallback> callback) const {
// Make a simple dialog to grab creds
auto layout = new QGridLayout;
auto header_label =
new QLabel(QString("Authentication requested for: ") + realm);
header_label->setTextFormat(Qt::PlainText);
layout->addWidget(header_label, 0, 0, 1, 2, Qt::AlignCenter);
layout->addWidget(new QLabel("Username:"), 1, 0);
auto username = new QLineEdit;
layout->addWidget(username, 1, 1);
layout->setColumnStretch(1, 1);
layout->addWidget(new QLabel("Password:"), 2, 0);
auto password = new QLineEdit;
password->setEchoMode(QLineEdit::Password);
layout->addWidget(password, 2, 1);
auto buttons = new QDialogButtonBox;
buttons->addButton(QDialogButtonBox::Ok);
buttons->addButton(QDialogButtonBox::Cancel);
layout->addWidget(buttons, 3, 0, 1, 2, Qt::AlignCenter);
auto dialog = new QDialog();
dialog->setWindowTitle("Authentication Requested");
dialog->setLayout(layout);
connect(buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked,
dialog, &QDialog::accept);
connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
dialog, &QDialog::reject);

if (dialog->exec() == QDialog::Accepted) {
// TODO(cretz): downstream issue:
// https://bitbucket.org/chromiumembedded/cef/issues/2275
if (username->text().isEmpty()) {
QMessageBox::critical(dialog, "Empty Username",
"Empty usernames are not currently supported");
// Defer a retry
QTimer::singleShot(0, [=]() { AuthRequest(realm, callback); });
return;
}
callback->Continue(CefString(username->text().toStdString()),
CefString(password->text().toStdString()));
} else {
callback->Cancel();
}

dialog->deleteLater();
}

} // namespace doogie
3 changes: 3 additions & 0 deletions src/cef/cef_widget.h
Expand Up @@ -148,6 +148,9 @@ class CefWidget : public CefBaseWidget {

void InitBrowser(const Bubble& bubble, const QString& url);

void AuthRequest(const QString& realm,
CefRefPtr<CefAuthCallback> callback) const;

CefRefPtr<CefHandler> handler_;
CefRefPtr<CefBrowser> browser_;
CefRefPtr<CefHandler> dev_tools_handler_;
Expand Down
24 changes: 24 additions & 0 deletions src/tests/integration/harness.js
Expand Up @@ -33,9 +33,33 @@ exports.Harness = class Harness {
return new Promise((resolve, reject) => {
const resServe = http.createServer((req, res) => {
const reqUrl = url.parse(req.url, true)

// We'll ask for auth or check auth ("user"/"pass") if requested
if (reqUrl.query['basicAuth']) {
let success = false
if (req.headers['authorization']) {
const pieces = req.headers['authorization'].split(' ', 2)
if (pieces.length == 2) {
const creds = (new Buffer(pieces[1], 'base64')).toString().split(':', 2)
console.log('Creds:', creds)
success = creds.length == 2 && creds[0] === 'user' && creds[1] === 'pass'
}
}
// No auth head means ask and leave
if (!success) {
res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="Type \'user\' and \'pass\'"')
res.end('<html><body>HTTP basic auth requested</body></html>')
return
}
}

res.writeHead(200)

// We'll just return if it wants us to hang forever
if (reqUrl.query['loadForever']) return

// Read what was asked for
const stream = fs.createReadStream(
path.join(this.resourceDir, path.normalize(reqUrl.pathname)))
stream.once('error', e => {
Expand Down

0 comments on commit c870baf

Please sign in to comment.