casino 4.0.3 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/stylesheets/casino.scss +60 -1
- data/app/controllers/casino/login_attempts_controller.rb +10 -0
- data/app/controllers/casino/sessions_controller.rb +3 -0
- data/app/helpers/casino/sessions_helper.rb +14 -0
- data/app/models/casino/login_attempt.rb +11 -0
- data/app/models/casino/model_concern/browser_info.rb +14 -0
- data/app/models/casino/ticket_granting_ticket.rb +1 -11
- data/app/models/casino/user.rb +1 -0
- data/app/views/casino/kaminari/_next_page.html.erb +5 -0
- data/app/views/casino/kaminari/_paginator.html.erb +6 -0
- data/app/views/casino/kaminari/_prev_page.html.erb +5 -0
- data/app/views/casino/login_attempts/_table.html.erb +28 -0
- data/app/views/casino/login_attempts/index.html.erb +14 -0
- data/app/views/casino/sessions/index.html.erb +12 -5
- data/casino.gemspec +1 -0
- data/config/locales/de.yml +34 -0
- data/config/locales/en.yml +35 -1
- data/config/locales/fr.yml +16 -0
- data/config/locales/pt-BR.yml +16 -0
- data/config/locales/ru.yml +110 -0
- data/config/locales/zh-CN.yml +16 -0
- data/config/locales/zh-TW.yml +16 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20160502074450_create_login_attempts.rb +14 -0
- data/lib/casino/engine.rb +1 -0
- data/lib/casino/version.rb +1 -1
- data/spec/controllers/login_attempts_controller_spec.rb +35 -0
- data/spec/controllers/sessions_controller_spec.rb +121 -68
- data/spec/dummy/db/schema.rb +11 -2
- data/spec/features/login_attempts_spec.rb +24 -0
- data/spec/features/session_overview_spec.rb +12 -0
- data/spec/model/login_attempt_spec.rb +7 -0
- data/spec/model/ticket_granting_ticket_spec.rb +5 -29
- data/spec/support/factories/login_attempt_factory.rb +10 -0
- data/spec/support/has_browser_info.rb +29 -0
- data/spec/support/kaminari.rb +3 -0
- metadata +38 -2
data/config/locales/fr.yml
CHANGED
@@ -86,3 +86,19 @@ fr:
|
|
86
86
|
x_seconds:
|
87
87
|
one: une seconde
|
88
88
|
other: ! '%{count} secondes'
|
89
|
+
views:
|
90
|
+
pagination:
|
91
|
+
first: "« Première"
|
92
|
+
last: "Dernière »"
|
93
|
+
previous: "‹ Précédente"
|
94
|
+
next: "Suivante ›"
|
95
|
+
truncate: "…"
|
96
|
+
helpers:
|
97
|
+
page_entries_info:
|
98
|
+
one_page:
|
99
|
+
display_entries:
|
100
|
+
zero: "Aucun(e) %{entry_name} trouvé(e)s"
|
101
|
+
one: "Affichage de <b>1</b> %{entry_name}"
|
102
|
+
other: "Affichage des <b>%{count}</b> %{entry_name}"
|
103
|
+
more_pages:
|
104
|
+
display_entries: "%{entry_name} <b>%{first}</b> à <b>%{last}</b> affiché(e)s sur <b>%{total}</b> au total"
|
data/config/locales/pt-BR.yml
CHANGED
@@ -86,3 +86,19 @@ pt-BR:
|
|
86
86
|
x_seconds:
|
87
87
|
one: um segundo
|
88
88
|
other: ! '%{count} segundos'
|
89
|
+
views:
|
90
|
+
pagination:
|
91
|
+
first: "« Primeira"
|
92
|
+
last: "Última »"
|
93
|
+
previous: "‹ Anterior"
|
94
|
+
next: "Próxima ›"
|
95
|
+
truncate: "…"
|
96
|
+
helpers:
|
97
|
+
page_entries_info:
|
98
|
+
one_page:
|
99
|
+
display_entries:
|
100
|
+
zero: "Nenhum %{entry_name} encontrado(a)"
|
101
|
+
one: "Exibindo <b>1</b> %{entry_name}"
|
102
|
+
other: "Exibindo <b>%{count}</b> %{entry_name}"
|
103
|
+
more_pages:
|
104
|
+
display_entries: "Exibindo %{entry_name} <b>%{first} - %{last}</b> de <b>%{total}</b> no total"
|
@@ -0,0 +1,110 @@
|
|
1
|
+
ru:
|
2
|
+
login_credential_acceptor:
|
3
|
+
invalid_login_ticket: "Ваш запрос на авторизацию не содержит корректную информацию об авторизации."
|
4
|
+
invalid_login_credentials: "Неверное имя пользователя или пароль."
|
5
|
+
login:
|
6
|
+
label_username: "Имя пользователя"
|
7
|
+
label_password: "Пароль"
|
8
|
+
label_button: "Войти"
|
9
|
+
label_remember_me: "Запомнить меня"
|
10
|
+
notice: ""
|
11
|
+
service_not_allowed:
|
12
|
+
title: "Доступ для данного сервиса запрещен"
|
13
|
+
message: "Авторизация для сервиса \"%{service}\" не настроена. Если Вы считаете, что это — ошибка, пожалуйста, свяжитесь с администратором."
|
14
|
+
validate_otp:
|
15
|
+
title: "Двухфакторная аутентификация"
|
16
|
+
description: "Пожалуйста, введите корректный одноразовый пароль."
|
17
|
+
code: "Код"
|
18
|
+
submit: "Продолжить"
|
19
|
+
invalid_otp: "Введённый одноразовый пароль некорректен."
|
20
|
+
logout:
|
21
|
+
title: "Всего доброго!"
|
22
|
+
logged_out_without_url: "Сеанс работы завершен."
|
23
|
+
logged_out_with_url: "Сеанс работы заверешен. Пожалуйста, пройдите по ссылке:"
|
24
|
+
sessions:
|
25
|
+
title: "Добро пожаловать!"
|
26
|
+
currently_logged_in_as: "Вы авторизованы как <strong>%{username}</strong>."
|
27
|
+
label_logout_button: "Выйти"
|
28
|
+
your_active_sessions: "Ваши активные сеансы"
|
29
|
+
table:
|
30
|
+
column_browser: "Браузер"
|
31
|
+
column_services: "Сервисы"
|
32
|
+
column_activity: "Текущая активность"
|
33
|
+
current_session: "Текущий сеанс"
|
34
|
+
end_session: "Завершить сессию"
|
35
|
+
two_factor_authenticators:
|
36
|
+
title: "Двухфакторная аутентификация"
|
37
|
+
setup: "Настройка двухфакторной аутентификации"
|
38
|
+
description: "Двухфакторная авторизация требует ввода дополнительного одноразового пароля при каждой попытке авторизации. Одноразовый пароль может быть получен с помощью приложения <a href='http://support.google.com/accounts/bin/answer.py?hl=en&answer=1066447'>Google Authenticator</a> на Вашем мобильном устройстве."
|
39
|
+
instructions: "Если Вы используете Google Authenticator, распознайте расположенный ниже QR с помощью приложения на Вашем мобильном устройстве. Введите код подтверждения в текстовое поле ниже."
|
40
|
+
disabled: "Выключено"
|
41
|
+
enable: "Включить"
|
42
|
+
enabled: "Включено"
|
43
|
+
disable: "Выключить"
|
44
|
+
cancel: "Отмена"
|
45
|
+
secret: "Секретно"
|
46
|
+
code: "Код подтверждения"
|
47
|
+
submit: "Подтвердить и включить"
|
48
|
+
invalid_one_time_password: "Введенный одноразовый пароль некорректен."
|
49
|
+
invalid_two_factor_authenticator: "Время для двухфакторной авторизации истекло. Пожалуйста, следуйте инструкциям ниже."
|
50
|
+
successfully_activated: "Двухфакторная авторизация успешно подключена для данной учетной записи."
|
51
|
+
successfully_deleted: "Двухфакторная авторизация отключена для данной учетной записи."
|
52
|
+
datetime:
|
53
|
+
ago: "%{datetime} назад"
|
54
|
+
distance_in_words:
|
55
|
+
about_x_hours:
|
56
|
+
few: около %{count} часов
|
57
|
+
many: около %{count} часов
|
58
|
+
one: около %{count} часа
|
59
|
+
other: около %{count} часа
|
60
|
+
about_x_months:
|
61
|
+
few: около %{count} месяцев
|
62
|
+
many: около %{count} месяцев
|
63
|
+
one: около %{count} месяца
|
64
|
+
other: около %{count} месяца
|
65
|
+
about_x_years:
|
66
|
+
few: около %{count} лет
|
67
|
+
many: около %{count} лет
|
68
|
+
one: около %{count} года
|
69
|
+
other: около %{count} лет
|
70
|
+
almost_x_years:
|
71
|
+
one: почти 1 год
|
72
|
+
few: почти %{count} года
|
73
|
+
many: почти %{count} лет
|
74
|
+
other: почти %{count} лет
|
75
|
+
half_a_minute: меньше минуты
|
76
|
+
less_than_x_minutes:
|
77
|
+
few: меньше %{count} минут
|
78
|
+
many: меньше %{count} минут
|
79
|
+
one: меньше %{count} минуты
|
80
|
+
other: меньше %{count} минуты
|
81
|
+
less_than_x_seconds:
|
82
|
+
few: меньше %{count} секунд
|
83
|
+
many: меньше %{count} секунд
|
84
|
+
one: меньше %{count} секунды
|
85
|
+
other: меньше %{count} секунды
|
86
|
+
over_x_years:
|
87
|
+
few: больше %{count} лет
|
88
|
+
many: больше %{count} лет
|
89
|
+
one: больше %{count} года
|
90
|
+
other: больше %{count} лет
|
91
|
+
x_days:
|
92
|
+
few: "%{count} дня"
|
93
|
+
many: "%{count} дней"
|
94
|
+
one: "%{count} день"
|
95
|
+
other: "%{count} дня"
|
96
|
+
x_minutes:
|
97
|
+
few: "%{count} минуты"
|
98
|
+
many: "%{count} минут"
|
99
|
+
one: "%{count} минуту"
|
100
|
+
other: "%{count} минуты"
|
101
|
+
x_months:
|
102
|
+
few: "%{count} месяца"
|
103
|
+
many: "%{count} месяцев"
|
104
|
+
one: "%{count} месяц"
|
105
|
+
other: "%{count} месяца"
|
106
|
+
x_seconds:
|
107
|
+
few: "%{count} секунды"
|
108
|
+
many: "%{count} секунд"
|
109
|
+
one: "%{count} секунду"
|
110
|
+
other: "%{count} секунды"
|
data/config/locales/zh-CN.yml
CHANGED
@@ -86,3 +86,19 @@ zh-CN:
|
|
86
86
|
x_seconds:
|
87
87
|
one: 一秒
|
88
88
|
other: ! '%{count}秒'
|
89
|
+
views:
|
90
|
+
pagination:
|
91
|
+
first: "« 第一页"
|
92
|
+
last: "最后一页 »"
|
93
|
+
previous: "‹ 上一页"
|
94
|
+
next: "下一页 ›"
|
95
|
+
truncate: "…"
|
96
|
+
helpers:
|
97
|
+
page_entries_info:
|
98
|
+
one_page:
|
99
|
+
display_entries:
|
100
|
+
zero: "没有任何 %{entry_name}"
|
101
|
+
one: "显示 <b>1</b> 个 %{entry_name}"
|
102
|
+
other: "显示 <b>全部 %{count}</b> 个 %{entry_name}"
|
103
|
+
more_pages:
|
104
|
+
display_entries: "显示 <b>%{total}</b> 个 %{entry_name} 中的第 <b>%{first} - %{last}</b> 个"
|
data/config/locales/zh-TW.yml
CHANGED
@@ -86,3 +86,19 @@ zh-TW:
|
|
86
86
|
x_seconds:
|
87
87
|
one: 一秒
|
88
88
|
other: ! '%{count}秒'
|
89
|
+
views:
|
90
|
+
pagination:
|
91
|
+
first: "« 第一頁"
|
92
|
+
last: "最後一頁 »"
|
93
|
+
previous: "‹ 上一頁"
|
94
|
+
next: "下一頁 ›"
|
95
|
+
truncate: "…"
|
96
|
+
helpers:
|
97
|
+
page_entries_info:
|
98
|
+
one_page:
|
99
|
+
display_entries:
|
100
|
+
zero: "沒有任何 %{entry_name}"
|
101
|
+
one: "顯示 <b>1</b> 筆 %{entry_name}"
|
102
|
+
other: "顯示 <b>全部 %{count}</b> 筆 %{entry_name}"
|
103
|
+
more_pages:
|
104
|
+
display_entries: "顯示 <b>%{total}</b> 筆 %{entry_name} 中的第 <b>%{first} - %{last}</b> 筆"
|
data/config/routes.rb
CHANGED
@@ -9,6 +9,8 @@ CASino::Engine.routes.draw do
|
|
9
9
|
get 'logout' => 'sessions#logout'
|
10
10
|
post 'validate_otp' => 'sessions#validate_otp'
|
11
11
|
|
12
|
+
resources :login_attempts, only: [:index]
|
13
|
+
|
12
14
|
get 'destroy-other-sessions' => 'sessions#destroy_others'
|
13
15
|
|
14
16
|
get 'validate' => 'service_tickets#validate'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateLoginAttempts < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :casino_login_attempts do |t|
|
4
|
+
t.integer :user_id, null: true
|
5
|
+
t.string :username, null: false
|
6
|
+
t.boolean :successful, default: false
|
7
|
+
|
8
|
+
t.string :user_ip
|
9
|
+
t.text :user_agent
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/casino/engine.rb
CHANGED
data/lib/casino/version.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CASino::LoginAttemptsController do
|
4
|
+
routes { CASino::Engine.routes }
|
5
|
+
|
6
|
+
describe 'GET #index' do
|
7
|
+
context 'with ticket granting ticket' do
|
8
|
+
let(:ticket_granting_ticket) { FactoryGirl.create :ticket_granting_ticket }
|
9
|
+
let(:login_attempt) { FactoryGirl.create :login_attempt, user: ticket_granting_ticket.user }
|
10
|
+
let(:old_login_attempt) do
|
11
|
+
FactoryGirl.create :login_attempt, user: ticket_granting_ticket.user, created_at: 10.weeks.ago
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
sign_in(ticket_granting_ticket)
|
16
|
+
login_attempt.touch
|
17
|
+
FactoryGirl.create :login_attempt
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'assigns current users login attempts @login_attempts' do
|
21
|
+
get :index
|
22
|
+
|
23
|
+
expect(assigns(:login_attempts)).to eq([login_attempt, old_login_attempt])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'without a ticket-granting ticket' do
|
28
|
+
it 'redirects to the login page' do
|
29
|
+
get :index
|
30
|
+
|
31
|
+
response.should redirect_to(login_path)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -2,8 +2,10 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe CASino::SessionsController do
|
4
4
|
include CASino::Engine.routes.url_helpers
|
5
|
+
|
6
|
+
routes { CASino::Engine.routes }
|
7
|
+
|
5
8
|
let(:params) { { } }
|
6
|
-
let(:request_options) { params.merge(use_route: :casino) }
|
7
9
|
let(:user_agent) { 'YOLOBrowser 420.00'}
|
8
10
|
|
9
11
|
before(:each) do
|
@@ -20,14 +22,14 @@ describe CASino::SessionsController do
|
|
20
22
|
let(:params) { { service: service } }
|
21
23
|
|
22
24
|
it 'renders the service_not_allowed template' do
|
23
|
-
get :new,
|
25
|
+
get :new, params
|
24
26
|
response.should render_template(:service_not_allowed)
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
30
|
context 'when logged out' do
|
29
31
|
it 'renders the new template' do
|
30
|
-
get :new,
|
32
|
+
get :new, params
|
31
33
|
response.should render_template(:new)
|
32
34
|
end
|
33
35
|
|
@@ -37,7 +39,7 @@ describe CASino::SessionsController do
|
|
37
39
|
let(:params) { { service: service, gateway: 'true' } }
|
38
40
|
|
39
41
|
it 'redirects to the service' do
|
40
|
-
get :new,
|
42
|
+
get :new, params
|
41
43
|
response.should redirect_to(service)
|
42
44
|
end
|
43
45
|
end
|
@@ -46,7 +48,7 @@ describe CASino::SessionsController do
|
|
46
48
|
let(:params) { { gateway: 'true' } }
|
47
49
|
|
48
50
|
it 'renders the new template' do
|
49
|
-
get :new,
|
51
|
+
get :new, params
|
50
52
|
response.should render_template(:new)
|
51
53
|
end
|
52
54
|
end
|
@@ -64,7 +66,7 @@ describe CASino::SessionsController do
|
|
64
66
|
let(:ticket_granting_ticket) { FactoryGirl.create :ticket_granting_ticket, :awaiting_two_factor_authentication }
|
65
67
|
|
66
68
|
it 'renders the new template' do
|
67
|
-
get :new,
|
69
|
+
get :new, params
|
68
70
|
response.should render_template(:new)
|
69
71
|
end
|
70
72
|
end
|
@@ -76,7 +78,7 @@ describe CASino::SessionsController do
|
|
76
78
|
end
|
77
79
|
|
78
80
|
it 'renders the new template' do
|
79
|
-
get :new,
|
81
|
+
get :new, params
|
80
82
|
response.should render_template(:new)
|
81
83
|
end
|
82
84
|
end
|
@@ -86,24 +88,24 @@ describe CASino::SessionsController do
|
|
86
88
|
let(:params) { { service: service } }
|
87
89
|
|
88
90
|
it 'redirects to the service' do
|
89
|
-
get :new,
|
91
|
+
get :new, params
|
90
92
|
response.location.should =~ /^#{Regexp.escape service}\?ticket=ST-/
|
91
93
|
end
|
92
94
|
|
93
95
|
it 'generates a service ticket' do
|
94
96
|
lambda do
|
95
|
-
get :new,
|
97
|
+
get :new, params
|
96
98
|
end.should change(CASino::ServiceTicket, :count).by(1)
|
97
99
|
end
|
98
100
|
|
99
101
|
it 'does not set the issued_from_credentials flag on the service ticket' do
|
100
|
-
get :new,
|
102
|
+
get :new, params
|
101
103
|
CASino::ServiceTicket.last.should_not be_issued_from_credentials
|
102
104
|
end
|
103
105
|
|
104
106
|
context 'with renew parameter' do
|
105
107
|
it 'renders the new template' do
|
106
|
-
get :new,
|
108
|
+
get :new, params.merge(renew: 'true')
|
107
109
|
response.should render_template(:new)
|
108
110
|
end
|
109
111
|
end
|
@@ -114,7 +116,7 @@ describe CASino::SessionsController do
|
|
114
116
|
let(:params) { { service: service } }
|
115
117
|
|
116
118
|
it 'does not remove the attributes' do
|
117
|
-
get :new,
|
119
|
+
get :new, params
|
118
120
|
response.location.should =~ /^#{Regexp.escape service}&ticket=ST-/
|
119
121
|
end
|
120
122
|
end
|
@@ -124,20 +126,20 @@ describe CASino::SessionsController do
|
|
124
126
|
let(:params) { { service: service } }
|
125
127
|
|
126
128
|
it 'redirects to the session overview' do
|
127
|
-
get :new,
|
129
|
+
get :new, params
|
128
130
|
response.should redirect_to(sessions_path)
|
129
131
|
end
|
130
132
|
end
|
131
133
|
|
132
134
|
context 'without a service' do
|
133
135
|
it 'redirects to the session overview' do
|
134
|
-
get :new,
|
136
|
+
get :new, params
|
135
137
|
response.should redirect_to(sessions_path)
|
136
138
|
end
|
137
139
|
|
138
140
|
it 'does not generate a service ticket' do
|
139
141
|
lambda do
|
140
|
-
get :new,
|
142
|
+
get :new, params
|
141
143
|
end.should change(CASino::ServiceTicket, :count).by(0)
|
142
144
|
end
|
143
145
|
|
@@ -149,7 +151,7 @@ describe CASino::SessionsController do
|
|
149
151
|
end
|
150
152
|
|
151
153
|
it 'renders the new template' do
|
152
|
-
get :new,
|
154
|
+
get :new, params
|
153
155
|
response.should render_template(:new)
|
154
156
|
end
|
155
157
|
end
|
@@ -167,7 +169,7 @@ describe CASino::SessionsController do
|
|
167
169
|
describe 'POST "create"' do
|
168
170
|
context 'without a valid login ticket' do
|
169
171
|
it 'renders the new template' do
|
170
|
-
post :create,
|
172
|
+
post :create, params
|
171
173
|
response.should render_template(:new)
|
172
174
|
end
|
173
175
|
end
|
@@ -177,20 +179,35 @@ describe CASino::SessionsController do
|
|
177
179
|
let(:params) { { lt: expired_login_ticket.ticket }}
|
178
180
|
|
179
181
|
it 'renders the new template' do
|
180
|
-
post :create,
|
182
|
+
post :create, params
|
181
183
|
response.should render_template(:new)
|
182
184
|
end
|
183
185
|
end
|
184
186
|
|
185
187
|
context 'with a valid login ticket' do
|
186
188
|
let(:login_ticket) { FactoryGirl.create :login_ticket }
|
187
|
-
let(:
|
189
|
+
let(:username) { 'testuser' }
|
190
|
+
let(:params) { { lt: login_ticket.ticket, username: username, password: 'wrrooonnng' }}
|
191
|
+
let!(:user) { FactoryGirl.create :user, username: username }
|
188
192
|
|
189
193
|
context 'with invalid credentials' do
|
190
194
|
it 'renders the new template' do
|
191
|
-
post :create,
|
195
|
+
post :create, params
|
192
196
|
response.should render_template(:new)
|
193
197
|
end
|
198
|
+
|
199
|
+
it 'creates session log' do
|
200
|
+
expect do
|
201
|
+
post :create, params
|
202
|
+
end.to change { CASino::LoginAttempt.count }.by 1
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'assigns session log the correct attributes' do
|
206
|
+
post :create, params
|
207
|
+
|
208
|
+
expect(CASino::LoginAttempt.last.user).to eq user
|
209
|
+
expect(CASino::LoginAttempt.last.successful).to eq false
|
210
|
+
end
|
194
211
|
end
|
195
212
|
|
196
213
|
context 'with valid credentials' do
|
@@ -200,16 +217,29 @@ describe CASino::SessionsController do
|
|
200
217
|
let(:params) { { lt: login_ticket.ticket, username: username, password: 'foobar123', service: service } }
|
201
218
|
|
202
219
|
it 'creates a cookie' do
|
203
|
-
post :create,
|
220
|
+
post :create, params
|
204
221
|
response.cookies['tgt'].should_not be_nil
|
205
222
|
end
|
206
223
|
|
207
224
|
it 'saves user_ip' do
|
208
|
-
post :create,
|
225
|
+
post :create, params
|
209
226
|
tgt = CASino::TicketGrantingTicket.last
|
210
227
|
tgt.user_ip.should == '0.0.0.0'
|
211
228
|
end
|
212
229
|
|
230
|
+
it 'creates session log' do
|
231
|
+
expect do
|
232
|
+
post :create, params
|
233
|
+
end.to change { CASino::LoginAttempt.count }.by 1
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'assigns session log the correct attributes' do
|
237
|
+
post :create, params
|
238
|
+
|
239
|
+
expect(CASino::LoginAttempt.last.user.username).to eq username
|
240
|
+
expect(CASino::LoginAttempt.last.successful).to eq true
|
241
|
+
end
|
242
|
+
|
213
243
|
context 'with rememberMe set' do
|
214
244
|
let(:cookie_jar) { HashWithIndifferentAccess.new }
|
215
245
|
|
@@ -219,12 +249,12 @@ describe CASino::SessionsController do
|
|
219
249
|
end
|
220
250
|
|
221
251
|
it 'creates a cookie with an expiration date set' do
|
222
|
-
post :create,
|
252
|
+
post :create, params
|
223
253
|
cookie_jar['tgt']['expires'].should be_kind_of(Time)
|
224
254
|
end
|
225
255
|
|
226
256
|
it 'creates a long-term ticket-granting ticket' do
|
227
|
-
post :create,
|
257
|
+
post :create, params
|
228
258
|
tgt = CASino::TicketGrantingTicket.last
|
229
259
|
tgt.long_term.should == true
|
230
260
|
end
|
@@ -235,7 +265,7 @@ describe CASino::SessionsController do
|
|
235
265
|
let!(:two_factor_authenticator) { FactoryGirl.create :two_factor_authenticator, user: user }
|
236
266
|
|
237
267
|
it 'renders the validate_otp template' do
|
238
|
-
post :create,
|
268
|
+
post :create, params
|
239
269
|
response.should render_template(:validate_otp)
|
240
270
|
end
|
241
271
|
end
|
@@ -247,7 +277,7 @@ describe CASino::SessionsController do
|
|
247
277
|
let(:service) { 'http://www.example.org/' }
|
248
278
|
|
249
279
|
it 'renders the service_not_allowed template' do
|
250
|
-
post :create,
|
280
|
+
post :create, params
|
251
281
|
response.should render_template(:service_not_allowed)
|
252
282
|
end
|
253
283
|
end
|
@@ -260,7 +290,7 @@ describe CASino::SessionsController do
|
|
260
290
|
end
|
261
291
|
|
262
292
|
it 'renders the new template' do
|
263
|
-
post :create,
|
293
|
+
post :create, params
|
264
294
|
response.should render_template(:new)
|
265
295
|
end
|
266
296
|
end
|
@@ -269,25 +299,25 @@ describe CASino::SessionsController do
|
|
269
299
|
let(:service) { nil }
|
270
300
|
|
271
301
|
it 'redirects to the session overview' do
|
272
|
-
post :create,
|
302
|
+
post :create, params
|
273
303
|
response.should redirect_to(sessions_path)
|
274
304
|
end
|
275
305
|
|
276
306
|
it 'generates a ticket-granting ticket' do
|
277
307
|
lambda do
|
278
|
-
post :create,
|
308
|
+
post :create, params
|
279
309
|
end.should change(CASino::TicketGrantingTicket, :count).by(1)
|
280
310
|
end
|
281
311
|
|
282
312
|
context 'when the user does not exist yet' do
|
283
313
|
it 'generates exactly one user' do
|
284
314
|
lambda do
|
285
|
-
post :create,
|
315
|
+
post :create, params
|
286
316
|
end.should change(CASino::User, :count).by(1)
|
287
317
|
end
|
288
318
|
|
289
319
|
it 'sets the users attributes' do
|
290
|
-
post :create,
|
320
|
+
post :create, params
|
291
321
|
user = CASino::User.last
|
292
322
|
user.username.should == username
|
293
323
|
user.authenticator.should == authenticator
|
@@ -299,13 +329,13 @@ describe CASino::SessionsController do
|
|
299
329
|
|
300
330
|
it 'does not regenerate the user' do
|
301
331
|
lambda do
|
302
|
-
post :create,
|
332
|
+
post :create, params
|
303
333
|
end.should_not change(CASino::User, :count)
|
304
334
|
end
|
305
335
|
|
306
336
|
it 'updates the extra attributes' do
|
307
337
|
lambda do
|
308
|
-
post :create,
|
338
|
+
post :create, params
|
309
339
|
user.reload
|
310
340
|
end.should change(user, :extra_attributes)
|
311
341
|
end
|
@@ -316,24 +346,24 @@ describe CASino::SessionsController do
|
|
316
346
|
let(:service) { 'https://www.example.com' }
|
317
347
|
|
318
348
|
it 'redirects to the service' do
|
319
|
-
post :create,
|
349
|
+
post :create, params
|
320
350
|
response.location.should =~ /^#{Regexp.escape service}\/\?ticket=ST-/
|
321
351
|
end
|
322
352
|
|
323
353
|
it 'generates a service ticket' do
|
324
354
|
lambda do
|
325
|
-
post :create,
|
355
|
+
post :create, params
|
326
356
|
end.should change(CASino::ServiceTicket, :count).by(1)
|
327
357
|
end
|
328
358
|
|
329
359
|
it 'does set the issued_from_credentials flag on the service ticket' do
|
330
|
-
post :create,
|
360
|
+
post :create, params
|
331
361
|
CASino::ServiceTicket.last.should be_issued_from_credentials
|
332
362
|
end
|
333
363
|
|
334
364
|
it 'generates a ticket-granting ticket' do
|
335
365
|
lambda do
|
336
|
-
post :create,
|
366
|
+
post :create, params
|
337
367
|
end.should change(CASino::TicketGrantingTicket, :count).by(1)
|
338
368
|
end
|
339
369
|
end
|
@@ -360,12 +390,12 @@ describe CASino::SessionsController do
|
|
360
390
|
end
|
361
391
|
|
362
392
|
it 'redirects to the service' do
|
363
|
-
post :validate_otp,
|
393
|
+
post :validate_otp, params
|
364
394
|
response.location.should =~ /^#{Regexp.escape service}\?ticket=ST-/
|
365
395
|
end
|
366
396
|
|
367
397
|
it 'does activate the ticket-granting ticket' do
|
368
|
-
post :validate_otp,
|
398
|
+
post :validate_otp, params
|
369
399
|
ticket_granting_ticket.reload.should_not be_awaiting_two_factor_authentication
|
370
400
|
end
|
371
401
|
|
@@ -378,7 +408,7 @@ describe CASino::SessionsController do
|
|
378
408
|
end
|
379
409
|
|
380
410
|
it 'creates a cookie with an expiration date set' do
|
381
|
-
post :validate_otp,
|
411
|
+
post :validate_otp, params
|
382
412
|
cookie_jar['tgt']['expires'].should be_kind_of(Time)
|
383
413
|
end
|
384
414
|
end
|
@@ -390,7 +420,7 @@ describe CASino::SessionsController do
|
|
390
420
|
let(:service) { 'http://www.example.org/' }
|
391
421
|
|
392
422
|
it 'renders the service_not_allowed template' do
|
393
|
-
post :validate_otp,
|
423
|
+
post :validate_otp, params
|
394
424
|
response.should render_template(:service_not_allowed)
|
395
425
|
end
|
396
426
|
end
|
@@ -402,12 +432,12 @@ describe CASino::SessionsController do
|
|
402
432
|
end
|
403
433
|
|
404
434
|
it 'renders the validate_otp template' do
|
405
|
-
post :validate_otp,
|
435
|
+
post :validate_otp, params
|
406
436
|
response.should render_template(:validate_otp)
|
407
437
|
end
|
408
438
|
|
409
439
|
it 'does not activate the ticket-granting ticket' do
|
410
|
-
post :validate_otp,
|
440
|
+
post :validate_otp, params
|
411
441
|
ticket_granting_ticket.reload.should be_awaiting_two_factor_authentication
|
412
442
|
end
|
413
443
|
end
|
@@ -416,7 +446,7 @@ describe CASino::SessionsController do
|
|
416
446
|
|
417
447
|
context 'without a ticket-granting ticket' do
|
418
448
|
it 'redirects to the login page' do
|
419
|
-
post :validate_otp,
|
449
|
+
post :validate_otp, params
|
420
450
|
response.should redirect_to(login_path)
|
421
451
|
end
|
422
452
|
end
|
@@ -434,12 +464,12 @@ describe CASino::SessionsController do
|
|
434
464
|
end
|
435
465
|
|
436
466
|
it 'deletes the ticket-granting ticket' do
|
437
|
-
get :logout,
|
467
|
+
get :logout, params
|
438
468
|
CASino::TicketGrantingTicket.where(id: ticket_granting_ticket.id).first.should == nil
|
439
469
|
end
|
440
470
|
|
441
471
|
it 'renders the logout template' do
|
442
|
-
get :logout,
|
472
|
+
get :logout, params
|
443
473
|
response.should render_template(:logout)
|
444
474
|
end
|
445
475
|
|
@@ -447,7 +477,7 @@ describe CASino::SessionsController do
|
|
447
477
|
let(:url) { 'http://www.example.com' }
|
448
478
|
|
449
479
|
it 'assigns the URL' do
|
450
|
-
get :logout,
|
480
|
+
get :logout, params
|
451
481
|
assigns(:url).should == url
|
452
482
|
end
|
453
483
|
end
|
@@ -458,7 +488,7 @@ describe CASino::SessionsController do
|
|
458
488
|
|
459
489
|
context 'when whitelisted' do
|
460
490
|
it 'redirects to the service' do
|
461
|
-
get :logout,
|
491
|
+
get :logout, params
|
462
492
|
response.should redirect_to(url)
|
463
493
|
end
|
464
494
|
end
|
@@ -469,12 +499,12 @@ describe CASino::SessionsController do
|
|
469
499
|
end
|
470
500
|
|
471
501
|
it 'renders the logout template' do
|
472
|
-
get :logout,
|
502
|
+
get :logout, params
|
473
503
|
response.should render_template(:logout)
|
474
504
|
end
|
475
505
|
|
476
506
|
it 'does not assign the URL' do
|
477
|
-
get :logout,
|
507
|
+
get :logout, params
|
478
508
|
assigns(:url).should be_nil
|
479
509
|
end
|
480
510
|
end
|
@@ -483,7 +513,7 @@ describe CASino::SessionsController do
|
|
483
513
|
|
484
514
|
context 'without a ticket-granting ticket' do
|
485
515
|
it 'renders the logout template' do
|
486
|
-
get :logout,
|
516
|
+
get :logout, params
|
487
517
|
response.should render_template(:logout)
|
488
518
|
end
|
489
519
|
end
|
@@ -501,7 +531,7 @@ describe CASino::SessionsController do
|
|
501
531
|
|
502
532
|
context 'without a two-factor authenticator registered' do
|
503
533
|
it 'does not assign any two-factor authenticators' do
|
504
|
-
get :index,
|
534
|
+
get :index, params
|
505
535
|
assigns(:two_factor_authenticators).should == []
|
506
536
|
end
|
507
537
|
end
|
@@ -510,7 +540,7 @@ describe CASino::SessionsController do
|
|
510
540
|
let!(:two_factor_authenticator) { FactoryGirl.create :two_factor_authenticator, :inactive, user: user }
|
511
541
|
|
512
542
|
it 'does not assign any two-factor authenticators' do
|
513
|
-
get :index,
|
543
|
+
get :index, params
|
514
544
|
assigns(:two_factor_authenticators).should == []
|
515
545
|
end
|
516
546
|
end
|
@@ -520,7 +550,7 @@ describe CASino::SessionsController do
|
|
520
550
|
let!(:other_two_factor_authenticator) { FactoryGirl.create :two_factor_authenticator }
|
521
551
|
|
522
552
|
it 'does assign the two-factor authenticator' do
|
523
|
-
get :index,
|
553
|
+
get :index, params
|
524
554
|
assigns(:two_factor_authenticators).should == [two_factor_authenticator]
|
525
555
|
end
|
526
556
|
end
|
@@ -534,7 +564,7 @@ describe CASino::SessionsController do
|
|
534
564
|
let(:ticket_granting_ticket) { FactoryGirl.create :ticket_granting_ticket, user: user }
|
535
565
|
|
536
566
|
it 'assigns both ticket granting tickets' do
|
537
|
-
get :index,
|
567
|
+
get :index, params
|
538
568
|
assigns(:ticket_granting_tickets).should == [ticket_granting_ticket, other_ticket_granting_ticket]
|
539
569
|
end
|
540
570
|
end
|
@@ -544,16 +574,39 @@ describe CASino::SessionsController do
|
|
544
574
|
let(:tgt) { ticket_granting_ticket.ticket }
|
545
575
|
|
546
576
|
it 'does not assign the other ticket granting ticket' do
|
547
|
-
get :index,
|
577
|
+
get :index, params
|
548
578
|
assigns(:ticket_granting_tickets).should == [ticket_granting_ticket]
|
549
579
|
end
|
550
580
|
end
|
551
581
|
end
|
582
|
+
|
583
|
+
describe 'last login attempts' do
|
584
|
+
let(:ticket_granting_ticket) { FactoryGirl.create :ticket_granting_ticket }
|
585
|
+
|
586
|
+
let(:login_attempts) do
|
587
|
+
6.times.map do |counter|
|
588
|
+
FactoryGirl.create :login_attempt, user: ticket_granting_ticket.user,
|
589
|
+
created_at: counter.minutes.ago
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
before do
|
594
|
+
sign_in(ticket_granting_ticket)
|
595
|
+
|
596
|
+
login_attempts
|
597
|
+
end
|
598
|
+
|
599
|
+
it 'assigns last five login attempts' do
|
600
|
+
get :index, params
|
601
|
+
|
602
|
+
expect(assigns(:login_attempts)).to eq login_attempts.sort_by(&:created_at).from(1).to(6).reverse
|
603
|
+
end
|
604
|
+
end
|
552
605
|
end
|
553
606
|
|
554
607
|
context 'without a ticket-granting ticket' do
|
555
608
|
it 'redirects to the login page' do
|
556
|
-
get :index,
|
609
|
+
get :index, params
|
557
610
|
response.should redirect_to(login_path)
|
558
611
|
end
|
559
612
|
end
|
@@ -575,17 +628,17 @@ describe CASino::SessionsController do
|
|
575
628
|
|
576
629
|
it 'deletes exactly one ticket-granting ticket' do
|
577
630
|
lambda do
|
578
|
-
delete :destroy,
|
631
|
+
delete :destroy, params
|
579
632
|
end.should change(CASino::TicketGrantingTicket, :count).by(-1)
|
580
633
|
end
|
581
634
|
|
582
635
|
it 'deletes the ticket-granting ticket' do
|
583
|
-
delete :destroy,
|
636
|
+
delete :destroy, params
|
584
637
|
CASino::TicketGrantingTicket.where(id: params[:id]).length.should == 0
|
585
638
|
end
|
586
639
|
|
587
640
|
it 'redirects to the session overview' do
|
588
|
-
delete :destroy,
|
641
|
+
delete :destroy, params
|
589
642
|
response.should redirect_to(sessions_path)
|
590
643
|
end
|
591
644
|
end
|
@@ -594,12 +647,12 @@ describe CASino::SessionsController do
|
|
594
647
|
let(:params) { { id: 99999 } }
|
595
648
|
it 'does not delete a ticket-granting ticket' do
|
596
649
|
lambda do
|
597
|
-
delete :destroy,
|
650
|
+
delete :destroy, params
|
598
651
|
end.should_not change(CASino::TicketGrantingTicket, :count)
|
599
652
|
end
|
600
653
|
|
601
654
|
it 'redirects to the session overview' do
|
602
|
-
delete :destroy,
|
655
|
+
delete :destroy, params
|
603
656
|
response.should redirect_to(sessions_path)
|
604
657
|
end
|
605
658
|
end
|
@@ -610,12 +663,12 @@ describe CASino::SessionsController do
|
|
610
663
|
|
611
664
|
it 'does not delete a ticket-granting ticket' do
|
612
665
|
lambda do
|
613
|
-
delete :destroy,
|
666
|
+
delete :destroy, params
|
614
667
|
end.should_not change(CASino::TicketGrantingTicket, :count)
|
615
668
|
end
|
616
669
|
|
617
670
|
it 'redirects to the session overview' do
|
618
|
-
delete :destroy,
|
671
|
+
delete :destroy, params
|
619
672
|
response.should redirect_to(sessions_path)
|
620
673
|
end
|
621
674
|
end
|
@@ -637,12 +690,12 @@ describe CASino::SessionsController do
|
|
637
690
|
|
638
691
|
it 'deletes all other ticket-granting tickets' do
|
639
692
|
lambda do
|
640
|
-
get :destroy_others,
|
693
|
+
get :destroy_others, params
|
641
694
|
end.should change(CASino::TicketGrantingTicket, :count).by(-3)
|
642
695
|
end
|
643
696
|
|
644
697
|
it 'redirects to the session overview' do
|
645
|
-
get :destroy_others,
|
698
|
+
get :destroy_others, params
|
646
699
|
response.should redirect_to(sessions_path)
|
647
700
|
end
|
648
701
|
|
@@ -650,7 +703,7 @@ describe CASino::SessionsController do
|
|
650
703
|
let(:url) { 'http://www.example.com' }
|
651
704
|
|
652
705
|
it 'redirects to the service' do
|
653
|
-
get :destroy_others,
|
706
|
+
get :destroy_others, params
|
654
707
|
response.should redirect_to(url)
|
655
708
|
end
|
656
709
|
end
|
@@ -661,7 +714,7 @@ describe CASino::SessionsController do
|
|
661
714
|
let(:url) { 'http://www.example.com' }
|
662
715
|
|
663
716
|
it 'redirects to the service' do
|
664
|
-
get :destroy_others,
|
717
|
+
get :destroy_others, params
|
665
718
|
response.should redirect_to(url)
|
666
719
|
end
|
667
720
|
end
|