summaryrefslogtreecommitdiff
path: root/users/test
diff options
context:
space:
mode:
authorjessib <jessib@riseup.net>2013-12-17 12:02:07 -0800
committerjessib <jessib@riseup.net>2013-12-17 12:02:07 -0800
commit98a247acb4d1be484c2982d48ec038eed3de3d55 (patch)
treef176092fa43145b9d8ce00a180fab70cf62da456 /users/test
parent634db9875cc8f6f6b9a4a83dfc6b8d53728eb2b5 (diff)
parent83cd3d95b78b6df9ac33a8ee169e570f4d3e2eeb (diff)
Merge branch 'develop' into feature/billing-no-authenticated-payments
Conflicts: billing/config/locales/en.yml
Diffstat (limited to 'users/test')
-rw-r--r--users/test/factories.rb12
-rw-r--r--users/test/functional/keys_controller_test.rb32
-rw-r--r--users/test/functional/sessions_controller_test.rb21
-rw-r--r--users/test/functional/users_controller_test.rb9
-rw-r--r--users/test/functional/v1/sessions_controller_test.rb19
-rw-r--r--users/test/integration/api/account_flow_test.rb34
-rwxr-xr-xusers/test/integration/api/python/umlauts.py79
-rw-r--r--users/test/integration/browser/account_test.rb114
-rw-r--r--users/test/support/auth_test_helper.rb14
-rw-r--r--users/test/support/integration_test_helper.rb6
-rw-r--r--users/test/unit/account_test.rb7
-rw-r--r--users/test/unit/identity_test.rb29
-rw-r--r--users/test/unit/local_email_test.rb31
-rw-r--r--users/test/unit/token_test.rb23
14 files changed, 355 insertions, 75 deletions
diff --git a/users/test/factories.rb b/users/test/factories.rb
index c87e290..ae00d43 100644
--- a/users/test/factories.rb
+++ b/users/test/factories.rb
@@ -19,6 +19,16 @@ FactoryGirl.define do
end
end
- factory :token
+ factory :token do
+ user
+ end
+ factory :pgp_key do
+ keyblock <<-EOPGP
+-----BEGIN PGP PUBLIC KEY BLOCK-----
++Dummy+PGP+KEY+++Dummy+PGP+KEY+++Dummy+PGP+KEY+++Dummy+PGP+KEY+
+#{SecureRandom.base64(4032)}
+-----END PGP PUBLIC KEY BLOCK-----
+ EOPGP
+ end
end
diff --git a/users/test/functional/keys_controller_test.rb b/users/test/functional/keys_controller_test.rb
new file mode 100644
index 0000000..863be93
--- /dev/null
+++ b/users/test/functional/keys_controller_test.rb
@@ -0,0 +1,32 @@
+require 'test_helper'
+
+class KeysControllerTest < ActionController::TestCase
+
+ test "get existing public key" do
+ public_key = 'my public key'
+ @user = stub_record :user, :public_key => public_key
+ User.stubs(:find_by_login).with(@user.login).returns(@user)
+ get :show, :login => @user.login
+ assert_response :success
+ assert_equal "text/text", response.content_type
+ assert_equal public_key, response.body
+ end
+
+ test "get non-existing public key for user" do
+ # this isn't a scenerio that should generally occur.
+ @user = stub_record :user
+ User.stubs(:find_by_login).with(@user.login).returns(@user)
+ get :show, :login => @user.login
+ assert_response :success
+ assert_equal "text/text", response.content_type
+ assert_equal '', response.body.strip
+ end
+
+ test "get public key for non-existing user" do
+ # raise 404 error if user doesn't exist (doesn't need to be this routing error, but seems fine to assume for now):
+ assert_raise(ActionController::RoutingError) {
+ get :show, :login => 'asdkljslksjfdlskfj'
+ }
+ end
+
+end
diff --git a/users/test/functional/sessions_controller_test.rb b/users/test/functional/sessions_controller_test.rb
index a630e6e..8b49005 100644
--- a/users/test/functional/sessions_controller_test.rb
+++ b/users/test/functional/sessions_controller_test.rb
@@ -17,6 +17,13 @@ class SessionsControllerTest < ActionController::TestCase
assert_template "sessions/new"
end
+ test "redirect to root_url if logged in" do
+ login
+ get :new
+ assert_response :redirect
+ assert_redirected_to root_url
+ end
+
test "renders json" do
get :new, :format => :json
assert_response :success
@@ -41,20 +48,12 @@ class SessionsControllerTest < ActionController::TestCase
assert_json_error :login => I18n.t(:all_strategies_failed)
end
- test "logout should reset warden user" do
- expect_warden_logout
+ test "destory should logout" do
+ login
+ expect_logout
delete :destroy
assert_response :redirect
assert_redirected_to root_url
end
- def expect_warden_logout
- raw = mock('raw session') do
- expects(:inspect)
- end
- request.env['warden'].expects(:raw_session).returns(raw)
- request.env['warden'].expects(:logout)
- end
-
-
end
diff --git a/users/test/functional/users_controller_test.rb b/users/test/functional/users_controller_test.rb
index 052de04..9c5f8d9 100644
--- a/users/test/functional/users_controller_test.rb
+++ b/users/test/functional/users_controller_test.rb
@@ -77,7 +77,11 @@ class UsersControllerTest < ActionController::TestCase
test "admin can destroy user" do
user = find_record :user
+
+ # we destroy the user record and the associated data...
user.expects(:destroy)
+ Identity.expects(:disable_all_for).with(user)
+ Ticket.expects(:destroy_all_from).with(user)
login :is_admin? => true
delete :destroy, :id => user.id
@@ -88,9 +92,14 @@ class UsersControllerTest < ActionController::TestCase
test "user can cancel account" do
user = find_record :user
+
+ # we destroy the user record and the associated data...
user.expects(:destroy)
+ Identity.expects(:disable_all_for).with(user)
+ Ticket.expects(:destroy_all_from).with(user)
login user
+ expect_logout
delete :destroy, :id => @current_user.id
assert_response :redirect
diff --git a/users/test/functional/v1/sessions_controller_test.rb b/users/test/functional/v1/sessions_controller_test.rb
index ff9fca1..4200e8f 100644
--- a/users/test/functional/v1/sessions_controller_test.rb
+++ b/users/test/functional/v1/sessions_controller_test.rb
@@ -52,26 +52,11 @@ class V1::SessionsControllerTest < ActionController::TestCase
assert_equal @user.id, token.user_id
end
- test "logout should reset session" do
- expect_warden_logout
- delete :destroy
- assert_response 204
- end
-
- test "logout should destroy token" do
+ test "destroy should logout" do
login
- expect_warden_logout
- @token.expects(:destroy)
+ expect_logout
delete :destroy
assert_response 204
end
- def expect_warden_logout
- raw = mock('raw session') do
- expects(:inspect)
- end
- request.env['warden'].expects(:raw_session).returns(raw)
- request.env['warden'].expects(:logout)
- end
-
end
diff --git a/users/test/integration/api/account_flow_test.rb b/users/test/integration/api/account_flow_test.rb
index e41befa..edd0859 100644
--- a/users/test/integration/api/account_flow_test.rb
+++ b/users/test/integration/api/account_flow_test.rb
@@ -96,27 +96,41 @@ class AccountFlowTest < RackTest
assert server_auth["M2"]
end
- test "update user" do
+ test "prevent changing login without changing password_verifier" do
server_auth = @srp.authenticate(self)
- test_public_key = 'asdlfkjslfdkjasd'
original_login = @user.login
new_login = 'zaph'
User.find_by_login(new_login).try(:destroy)
Identity.by_address.key(new_login + '@' + APP_CONFIG[:domain]).each do |identity|
identity.destroy
end
- put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => test_public_key, :login => new_login}, :format => :json
+ put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:login => new_login}, :format => :json
assert last_response.successful?
- assert_equal test_public_key, Identity.for(@user).keys[:pgp]
# does not change login if no password_verifier is present
assert_equal original_login, @user.login
- # eventually probably want to remove most of this into a non-integration functional test
- # should not overwrite public key:
- put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:blee => :blah}, :format => :json
- assert_equal test_public_key, Identity.for(@user).keys[:pgp]
- # should overwrite public key:
- put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => nil}, :format => :json
+ end
+
+ test "upload pgp key" do
+ server_auth = @srp.authenticate(self)
+ key = FactoryGirl.build :pgp_key
+ put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => key}, :format => :json
+ assert_equal key, Identity.for(@user).keys[:pgp]
+ end
+
+ # eventually probably want to remove most of this into a non-integration
+ # functional test
+ test "prevent uploading invalid key" do
+ server_auth = @srp.authenticate(self)
+ put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => :blah}, :format => :json
assert_nil Identity.for(@user).keys[:pgp]
end
+ test "prevent emptying public key" do
+ server_auth = @srp.authenticate(self)
+ key = FactoryGirl.build :pgp_key
+ put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => key}, :format => :json
+ put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => ""}, :format => :json
+ assert_equal key, Identity.for(@user).keys[:pgp]
+ end
+
end
diff --git a/users/test/integration/api/python/umlauts.py b/users/test/integration/api/python/umlauts.py
new file mode 100755
index 0000000..96fecbf
--- /dev/null
+++ b/users/test/integration/api/python/umlauts.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+# under development
+
+import requests
+import json
+import string
+import random
+import srp._pysrp as srp
+import binascii
+
+safe_unhexlify = lambda x: binascii.unhexlify(x) if (len(x) % 2 == 0) else binascii.unhexlify('0'+x)
+
+# using globals for now
+# server = 'https://dev.bitmask.net/1'
+server = 'http://api.lvh.me:3000/1'
+
+def run_tests():
+ login = 'test_' + id_generator()
+ password = id_generator() + "äöì" + id_generator()
+ usr = srp.User( login, password, srp.SHA256, srp.NG_1024 )
+ print_and_parse(signup(login, password))
+
+ auth = print_and_parse(authenticate(usr))
+ verify_or_debug(auth, usr)
+ assert usr.authenticated()
+
+
+# let's have some random name
+def id_generator(size=6, chars=string.ascii_lowercase + string.digits):
+ return ''.join(random.choice(chars) for x in range(size))
+
+# log the server communication
+def print_and_parse(response):
+ request = response.request
+ print request.method + ': ' + response.url
+ if hasattr(request, 'data'):
+ print " " + json.dumps(response.request.data)
+ print " -> " + response.text
+ try:
+ return json.loads(response.text)
+ except ValueError:
+ return None
+
+def signup(login, password):
+ salt, vkey = srp.create_salted_verification_key( login, password, srp.SHA256, srp.NG_1024 )
+ user_params = {
+ 'user[login]': login,
+ 'user[password_verifier]': binascii.hexlify(vkey),
+ 'user[password_salt]': binascii.hexlify(salt)
+ }
+ print json.dumps(user_params)
+ return requests.post(server + '/users.json', data = user_params, verify = False)
+
+def authenticate(usr):
+ session = requests.session()
+ uname, A = usr.start_authentication()
+ params = {
+ 'login': uname,
+ 'A': binascii.hexlify(A)
+ }
+ init = print_and_parse(session.post(server + '/sessions', data = params, verify=False))
+ M = usr.process_challenge( safe_unhexlify(init['salt']), safe_unhexlify(init['B']) )
+ return session.put(server + '/sessions/' + uname, verify = False,
+ data = {'client_auth': binascii.hexlify(M)})
+
+def verify_or_debug(auth, usr):
+ if ( 'errors' in auth ):
+ print ' u = "%x"' % usr.u
+ print ' x = "%x"' % usr.x
+ print ' v = "%x"' % usr.v
+ print ' S = "%x"' % usr.S
+ print ' K = "' + binascii.hexlify(usr.K) + '"'
+ print ' M = "' + binascii.hexlify(usr.M) + '"'
+ else:
+ usr.verify_session( safe_unhexlify(auth["M2"]) )
+
+run_tests()
diff --git a/users/test/integration/browser/account_test.rb b/users/test/integration/browser/account_test.rb
index 1deda45..4cefe35 100644
--- a/users/test/integration/browser/account_test.rb
+++ b/users/test/integration/browser/account_test.rb
@@ -6,6 +6,10 @@ class AccountTest < BrowserIntegrationTest
Capybara.current_driver = Capybara.javascript_driver
end
+ teardown do
+ Identity.destroy_all_disabled
+ end
+
test "normal account workflow" do
username, password = submit_signup
assert page.has_content?("Welcome #{username}")
@@ -19,46 +23,85 @@ class AccountTest < BrowserIntegrationTest
test "successful login" do
username, password = submit_signup
click_on 'Logout'
- click_on 'Log In'
- fill_in 'Username', with: username
- fill_in 'Password', with: password
- click_on 'Log In'
+ attempt_login(username, password)
assert page.has_content?("Welcome #{username}")
User.find_by_login(username).account.destroy
end
- test "change password" do
+ test "failed login" do
+ visit '/'
+ attempt_login("username", "wrong password")
+ assert_invalid_login(page)
+ end
+
+ test "account destruction" do
+ username, password = submit_signup
+ click_on I18n.t('account_settings')
+ click_on I18n.t('destroy_my_account')
+ assert page.has_content?(I18n.t('account_destroyed'))
+ attempt_login(username, password)
+ assert_invalid_login(page)
+ end
+
+ test "handle blocked after account destruction" do
+ username, password = submit_signup
+ click_on I18n.t('account_settings')
+ click_on I18n.t('destroy_my_account')
+ submit_signup(username)
+ assert page.has_content?('has already been taken')
+ end
+
+ test "default user actions" do
username, password = submit_signup
click_on "Account Settings"
- within('#update_login_and_password') do
- fill_in 'Password', with: "other password"
- fill_in 'Password confirmation', with: "other password"
- click_on 'Save'
+ assert page.has_content? I18n.t('destroy_my_account')
+ assert page.has_no_css? '#update_login_and_password'
+ assert page.has_no_css? '#update_pgp_key'
+ end
+
+ test "default admin actions" do
+ username, password = submit_signup
+ with_config admins: [username] do
+ click_on "Account Settings"
+ assert page.has_content? I18n.t('destroy_my_account')
+ assert page.has_no_css? '#update_login_and_password'
+ assert page.has_css? '#update_pgp_key'
+ end
+ end
+
+ test "change password" do
+ with_config user_actions: ['change_password'] do
+ username, password = submit_signup
+ click_on "Account Settings"
+ within('#update_login_and_password') do
+ fill_in 'Password', with: "other password"
+ fill_in 'Password confirmation', with: "other password"
+ click_on 'Save'
+ end
+ click_on 'Logout'
+ attempt_login(username, "other password")
+ assert page.has_content?("Welcome #{username}")
+ User.find_by_login(username).account.destroy
end
- click_on 'Logout'
- click_on 'Log In'
- fill_in 'Username', with: username
- fill_in 'Password', with: "other password"
- click_on 'Log In'
- assert page.has_content?("Welcome #{username}")
- User.find_by_login(username).account.destroy
end
test "change pgp key" do
- pgp_key = "My PGP Key Stub"
- username, password = submit_signup
- click_on "Account Settings"
- within('#update_pgp_key') do
- fill_in 'Public key', with: pgp_key
- click_on 'Save'
+ with_config user_actions: ['change_pgp_key'] do
+ pgp_key = FactoryGirl.build :pgp_key
+ username, password = submit_signup
+ click_on "Account Settings"
+ within('#update_pgp_key') do
+ fill_in 'Public key', with: pgp_key
+ click_on 'Save'
+ end
+ page.assert_selector 'input[value="Saving..."]'
+ # at some point we're done:
+ page.assert_no_selector 'input[value="Saving..."]'
+ assert page.has_field? 'Public key', with: pgp_key.to_s
+ user = User.find_by_login(username)
+ assert_equal pgp_key, user.public_key
+ user.account.destroy
end
- page.assert_selector 'input[value="Saving..."]'
- # at some point we're done:
- page.assert_no_selector 'input[value="Saving..."]'
- assert page.has_field? 'Public key', with: pgp_key
- user = User.find_by_login(username)
- assert_equal pgp_key, user.public_key
- user.account.destroy
end
@@ -81,6 +124,19 @@ class AccountTest < BrowserIntegrationTest
assert page.has_content?("server failed")
end
+ def attempt_login(username, password)
+ click_on 'Log In'
+ fill_in 'Username', with: username
+ fill_in 'Password', with: password
+ click_on 'Log In'
+ end
+
+ def assert_invalid_login(page)
+ assert page.has_selector? 'input.btn-primary.disabled'
+ assert page.has_content? I18n.t(:invalid_user_pass)
+ assert page.has_no_selector? 'input.btn-primary.disabled'
+ end
+
def inject_malicious_js
page.execute_script <<-EOJS
var calc = new srp.Calculate();
diff --git a/users/test/support/auth_test_helper.rb b/users/test/support/auth_test_helper.rb
index 609f115..50e9453 100644
--- a/users/test/support/auth_test_helper.rb
+++ b/users/test/support/auth_test_helper.rb
@@ -38,12 +38,26 @@ module AuthTestHelper
end
end
+ def expect_logout
+ expect_warden_logout
+ @token.expects(:destroy) if @token
+ end
+
protected
def header_for_token_auth
@token = find_record(:token, :authenticate => @current_user)
ActionController::HttpAuthentication::Token.encode_credentials @token.id
end
+
+ def expect_warden_logout
+ raw = mock('raw session') do
+ expects(:inspect)
+ end
+ request.env['warden'].expects(:raw_session).returns(raw)
+ request.env['warden'].expects(:logout)
+ end
+
end
class ActionController::TestCase
diff --git a/users/test/support/integration_test_helper.rb b/users/test/support/integration_test_helper.rb
index cfe72cf..51e47c6 100644
--- a/users/test/support/integration_test_helper.rb
+++ b/users/test/support/integration_test_helper.rb
@@ -1,7 +1,7 @@
module IntegrationTestHelper
- def submit_signup
- username = "test_#{SecureRandom.urlsafe_base64}".downcase
- password = SecureRandom.base64
+ def submit_signup(username = nil, password = nil)
+ username ||= "test_#{SecureRandom.urlsafe_base64}".downcase
+ password ||= SecureRandom.base64
visit '/users/new'
fill_in 'Username', with: username
fill_in 'Password', with: password
diff --git a/users/test/unit/account_test.rb b/users/test/unit/account_test.rb
index 94a9980..4fb3c3d 100644
--- a/users/test/unit/account_test.rb
+++ b/users/test/unit/account_test.rb
@@ -2,6 +2,10 @@ require 'test_helper'
class AccountTest < ActiveSupport::TestCase
+ teardown do
+ Identity.destroy_all_disabled
+ end
+
test "create a new account" do
user = Account.create(FactoryGirl.attributes_for(:user))
assert user.valid?
@@ -13,7 +17,8 @@ class AccountTest < ActiveSupport::TestCase
end
test "create and remove a user account" do
- assert_no_difference "Identity.count" do
+ # We keep an identity that will block the handle from being reused.
+ assert_difference "Identity.count" do
assert_no_difference "User.count" do
user = Account.create(FactoryGirl.attributes_for(:user))
user.account.destroy
diff --git a/users/test/unit/identity_test.rb b/users/test/unit/identity_test.rb
index 0842a77..eca104f 100644
--- a/users/test/unit/identity_test.rb
+++ b/users/test/unit/identity_test.rb
@@ -90,6 +90,35 @@ class IdentityTest < ActiveSupport::TestCase
assert id.errors.messages[:destination].include? "needs to be a valid email address"
end
+ test "disabled identity" do
+ id = Identity.for(@user)
+ id.disable
+ assert_equal @user.email_address, id.address
+ assert_equal nil, id.destination
+ assert_equal nil, id.user
+ assert !id.enabled?
+ assert id.valid?
+ end
+
+ test "disabled identity blocks handle" do
+ id = Identity.for(@user)
+ id.disable
+ id.save
+ other_user = find_record :user
+ taken = Identity.build_for other_user, address: id.address
+ assert !taken.valid?
+ Identity.destroy_all_disabled
+ end
+
+ test "destroy all disabled identities" do
+ id = Identity.for(@user)
+ id.disable
+ id.save
+ assert Identity.count > 0
+ Identity.destroy_all_disabled
+ assert_equal 0, Identity.disabled.count
+ end
+
def alias_name
@alias_name ||= Faker::Internet.user_name
end
diff --git a/users/test/unit/local_email_test.rb b/users/test/unit/local_email_test.rb
index b25f46f..20ee7f1 100644
--- a/users/test/unit/local_email_test.rb
+++ b/users/test/unit/local_email_test.rb
@@ -24,6 +24,37 @@ class LocalEmailTest < ActiveSupport::TestCase
assert_equal ["needs to end in @#{LocalEmail.domain}"], local.errors[:email]
end
+ test "blacklists rfc2142" do
+ black_listed = LocalEmail.new('hostmaster')
+ assert !black_listed.valid?
+ end
+
+ test "blacklists etc passwd" do
+ black_listed = LocalEmail.new('nobody')
+ assert !black_listed.valid?
+ end
+
+ test "whitelist overwrites automatic blacklists" do
+ with_config handle_whitelist: ['nobody', 'hostmaster'] do
+ white_listed = LocalEmail.new('nobody')
+ assert white_listed.valid?
+ white_listed = LocalEmail.new('hostmaster')
+ assert white_listed.valid?
+ end
+ end
+
+ test "blacklists from config" do
+ black_listed = LocalEmail.new('www-data')
+ assert !black_listed.valid?
+ end
+
+ test "blacklist from config overwrites whitelist" do
+ with_config handle_whitelist: ['www-data'] do
+ black_listed = LocalEmail.new('www-data')
+ assert !black_listed.valid?
+ end
+ end
+
def handle
@handle ||= Faker::Internet.user_name
end
diff --git a/users/test/unit/token_test.rb b/users/test/unit/token_test.rb
index f56c576..6c9f209 100644
--- a/users/test/unit/token_test.rb
+++ b/users/test/unit/token_test.rb
@@ -7,9 +7,6 @@ class ClientCertificateTest < ActiveSupport::TestCase
@user = find_record :user
end
- teardown do
- end
-
test "new token for user" do
sample = Token.new(:user_id => @user.id)
assert sample.valid?
@@ -61,6 +58,26 @@ class ClientCertificateTest < ActiveSupport::TestCase
end
end
+ test "Token.destroy_all_expired is noop if no expiry is set" do
+ expired = FactoryGirl.create :token, last_seen_at: 2.hours.ago
+ with_config auth: {} do
+ Token.destroy_all_expired
+ end
+ assert_equal expired, Token.find(expired.id)
+ end
+
+ test "Token.destroy_all_expired cleans up expired tokens only" do
+ expired = FactoryGirl.create :token, last_seen_at: 2.hours.ago
+ fresh = FactoryGirl.create :token
+ with_config auth: {token_expires_after: 60} do
+ Token.destroy_all_expired
+ end
+ assert_nil Token.find(expired.id)
+ assert_equal fresh, Token.find(fresh.id)
+ fresh.destroy
+ end
+
+
end