Permalink
Browse files

Added browser.authenticate for http basic authentication

  • Loading branch information...
halogenandtoast committed May 25, 2012
1 parent 6535c1b commit 5b5067f243e8722e57d475ba3e220b0f9c749939
@@ -6,6 +6,10 @@ def initialize(connection)
@connection = connection
end
+ def authenticate(username, password)
+ command("Authenticate", username, password)
+ end
+
def visit(url)
command "Visit", url
end
View
@@ -1,5 +1,6 @@
require 'spec_helper'
require 'capybara/driver/webkit'
+require 'base64'
describe Capybara::Driver::Webkit do
subject { Capybara::Driver::Webkit.new(@app, :browser => $webkit_browser) }
@@ -1711,4 +1712,30 @@ def which_for(character)
end.to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
end
end
+
+ describe "basic auth" do
+ before(:all) do
+ @app = lambda do |env|
+ if env["REQUEST_PATH"] == "/hello/world"
+ [200, {"Content-Type" => "text/html", "Content-Length" => "0"}, [""]]
+ else
+ if env["HTTP_AUTHORIZATION"]
+ header = env["HTTP_AUTHORIZATION"]
+ [200, {"Content-Type" => "text/html", "Content-Length" => header.length.to_s}, [header]]
+ else
+ html = "401 Unauthorized."
+ [401,
+ {"Content-Type" => "text/html", "Content-Length" => html.length.to_s, "WWW-Authenticate" => 'Basic realm="Secure Area"'},
+ [html]]
+ end
+ end
+ end
+ end
+
+ it "can authenticate a request" do
+ subject.browser.authenticate('user', 'password')
+ subject.visit("/")
+ subject.body.should include("Basic "+Base64.encode64("user:password").strip)
+ end
+ end
end
View
@@ -0,0 +1,18 @@
+#include "Authenticate.h"
+#include "WebPage.h"
+#include "NetworkAccessManager.h"
+
+Authenticate::Authenticate(WebPageManager *manager, QStringList &arguments, QObject *parent) : Command(manager, arguments, parent) {
+}
+
+void Authenticate::start() {
+ QString username = arguments()[0];
+ QString password = arguments()[1];
+
+ NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
+ networkAccessManager->setUserName(username);
+ networkAccessManager->setPassword(password);
+
+ emit finished(new Response(true));
+}
+
View
@@ -0,0 +1,12 @@
+#include "Command.h"
+
+class WebPage;
+
+class Authenticate : public Command {
+ Q_OBJECT
+
+ public:
+ Authenticate(WebPageManager *manager, QStringList &arguments, QObject *parent = 0);
+ virtual void start();
+};
+
View
@@ -29,6 +29,7 @@
#include "GetWindowHandles.h"
#include "GetWindowHandle.h"
#include "WebPageManager.h"
+#include "Authenticate.h"
CommandFactory::CommandFactory(WebPageManager *manager, QObject *parent) : QObject(parent) {
m_manager = manager;
@@ -1,9 +1,11 @@
#include "NetworkAccessManager.h"
#include "WebPage.h"
#include <iostream>
+#include <fstream>
NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManager(parent) {
+ connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), SLOT(provideAuthentication(QNetworkReply*,QAuthenticator*)));
}
QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, QIODevice * outgoingData = 0) {
@@ -27,3 +29,17 @@ void NetworkAccessManager::resetHeaders() {
m_headers.clear();
};
+void NetworkAccessManager::setUserName(const QString &userName) {
+ m_userName = userName;
+}
+
+void NetworkAccessManager::setPassword(const QString &password) {
+ m_password = password;
+}
+
+
+void NetworkAccessManager::provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator) {
+ Q_UNUSED(reply);
+ authenticator->setUser(m_userName);
+ authenticator->setPassword(m_password);
+}
@@ -10,10 +10,17 @@ class NetworkAccessManager : public QNetworkAccessManager {
NetworkAccessManager(QObject *parent = 0);
void addHeader(QString key, QString value);
void resetHeaders();
+ void setUserName(const QString &userName);
+ void setPassword(const QString &password);
protected:
QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * outgoingData);
+ QString m_userName;
+ QString m_password;
private:
QHash<QString, QString> m_headers;
+
+ private slots:
+ void provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);
};
View
@@ -30,3 +30,4 @@ CHECK_COMMAND(SetSkipImageLoading)
CHECK_COMMAND(WindowFocus)
CHECK_COMMAND(GetWindowHandles)
CHECK_COMMAND(GetWindowHandle)
+CHECK_COMMAND(Authenticate)
View
@@ -2,6 +2,7 @@ TEMPLATE = app
TARGET = webkit_server
DESTDIR = .
HEADERS = \
+ Authenticate.h \
IgnoreSslErrors.h \
ResizeWindow.h \
CurrentUrl.h \
@@ -45,6 +46,7 @@ HEADERS = \
GetWindowHandle.h \
SOURCES = \
+ Authenticate.cpp \
IgnoreSslErrors.cpp \
ResizeWindow.cpp \
CurrentUrl.cpp \

5 comments on commit 5b5067f

@samwgoldman

This comment has been minimized.

Show comment Hide comment
@samwgoldman

samwgoldman Jun 15, 2012

Will setting authentication persist for an entire test run, or will capybara-webkit reset it for each example? Can I unauthenticate? If the challenge fails, what happens?

Will setting authentication persist for an entire test run, or will capybara-webkit reset it for each example? Can I unauthenticate? If the challenge fails, what happens?

@halogenandtoast

This comment has been minimized.

Show comment Hide comment
@halogenandtoast

halogenandtoast Jun 15, 2012

Contributor

Currently I don't think it's being reset so it will persist. No you cannot unauthenticate with this commit. If the challenge fails it up to the application to return a response so it depends on what type of response your app will return. The typical response to return on a failed authentication is a 403, returning a 401 will cause an infinite loop since that would be asking for authentication again. I currently don't have a guard in for such a scenario.

Contributor

halogenandtoast replied Jun 15, 2012

Currently I don't think it's being reset so it will persist. No you cannot unauthenticate with this commit. If the challenge fails it up to the application to return a response so it depends on what type of response your app will return. The typical response to return on a failed authentication is a 403, returning a 401 will cause an infinite loop since that would be asking for authentication again. I currently don't have a guard in for such a scenario.

@halogenandtoast

This comment has been minimized.

Show comment Hide comment
@halogenandtoast

halogenandtoast Jun 15, 2012

Contributor

On the question of unauthenticating... how would you unauthenticate using a normal browser... that doesn't seem like a concern for an integration test.

Contributor

halogenandtoast replied Jun 15, 2012

On the question of unauthenticating... how would you unauthenticate using a normal browser... that doesn't seem like a concern for an integration test.

@halogenandtoast

This comment has been minimized.

Show comment Hide comment
@halogenandtoast

halogenandtoast Jun 15, 2012

Contributor

In between tests it will be reset. You may however see the following header:

HTTP_AUTHORIZATION: Basic Og==

Which is what would happen if you tried to authorize with an empty username and password.

Contributor

halogenandtoast replied Jun 15, 2012

In between tests it will be reset. You may however see the following header:

HTTP_AUTHORIZATION: Basic Og==

Which is what would happen if you tried to authorize with an empty username and password.

@sweatpantsninja

This comment has been minimized.

Show comment Hide comment
@sweatpantsninja

sweatpantsninja Jun 21, 2012

How does one access the browser object? I'm seeing this error
undefined local variable or method `browser' for #RSpec::Core::ExampleGroup::Nested_2::Nested_2:0xbfa62ec

for this code https://gist.github.com/2963178

How does one access the browser object? I'm seeing this error
undefined local variable or method `browser' for #RSpec::Core::ExampleGroup::Nested_2::Nested_2:0xbfa62ec

for this code https://gist.github.com/2963178

Please sign in to comment.