Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added browser.authenticate for http basic authentication

  • Loading branch information...
commit 5b5067f243e8722e57d475ba3e220b0f9c749939 1 parent 6535c1b
@halogenandtoast halogenandtoast authored
View
4 lib/capybara/driver/webkit/browser.rb
@@ -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
27 spec/driver_spec.rb
@@ -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
18 src/Authenticate.cpp
@@ -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
12 src/Authenticate.h
@@ -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
1  src/CommandFactory.cpp
@@ -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;
View
16 src/NetworkAccessManager.cpp
@@ -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);
+}
View
7 src/NetworkAccessManager.h
@@ -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
1  src/find_command.h
@@ -30,3 +30,4 @@ CHECK_COMMAND(SetSkipImageLoading)
CHECK_COMMAND(WindowFocus)
CHECK_COMMAND(GetWindowHandles)
CHECK_COMMAND(GetWindowHandle)
+CHECK_COMMAND(Authenticate)
View
2  src/webkit_server.pro
@@ -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

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

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

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

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

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.
Something went wrong with that request. Please try again.