casino 4.0.3 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/stylesheets/casino.scss +60 -1
  4. data/app/controllers/casino/login_attempts_controller.rb +10 -0
  5. data/app/controllers/casino/sessions_controller.rb +3 -0
  6. data/app/helpers/casino/sessions_helper.rb +14 -0
  7. data/app/models/casino/login_attempt.rb +11 -0
  8. data/app/models/casino/model_concern/browser_info.rb +14 -0
  9. data/app/models/casino/ticket_granting_ticket.rb +1 -11
  10. data/app/models/casino/user.rb +1 -0
  11. data/app/views/casino/kaminari/_next_page.html.erb +5 -0
  12. data/app/views/casino/kaminari/_paginator.html.erb +6 -0
  13. data/app/views/casino/kaminari/_prev_page.html.erb +5 -0
  14. data/app/views/casino/login_attempts/_table.html.erb +28 -0
  15. data/app/views/casino/login_attempts/index.html.erb +14 -0
  16. data/app/views/casino/sessions/index.html.erb +12 -5
  17. data/casino.gemspec +1 -0
  18. data/config/locales/de.yml +34 -0
  19. data/config/locales/en.yml +35 -1
  20. data/config/locales/fr.yml +16 -0
  21. data/config/locales/pt-BR.yml +16 -0
  22. data/config/locales/ru.yml +110 -0
  23. data/config/locales/zh-CN.yml +16 -0
  24. data/config/locales/zh-TW.yml +16 -0
  25. data/config/routes.rb +2 -0
  26. data/db/migrate/20160502074450_create_login_attempts.rb +14 -0
  27. data/lib/casino/engine.rb +1 -0
  28. data/lib/casino/version.rb +1 -1
  29. data/spec/controllers/login_attempts_controller_spec.rb +35 -0
  30. data/spec/controllers/sessions_controller_spec.rb +121 -68
  31. data/spec/dummy/db/schema.rb +11 -2
  32. data/spec/features/login_attempts_spec.rb +24 -0
  33. data/spec/features/session_overview_spec.rb +12 -0
  34. data/spec/model/login_attempt_spec.rb +7 -0
  35. data/spec/model/ticket_granting_ticket_spec.rb +5 -29
  36. data/spec/support/factories/login_attempt_factory.rb +10 -0
  37. data/spec/support/has_browser_info.rb +29 -0
  38. data/spec/support/kaminari.rb +3 -0
  39. metadata +38 -2
@@ -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"
@@ -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: "&laquo; Primeira"
92
+ last: "Última &raquo;"
93
+ previous: "&lsaquo; Anterior"
94
+ next: "Próxima &rsaquo;"
95
+ truncate: "&hellip;"
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}&nbsp;-&nbsp;%{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} секунды"
@@ -86,3 +86,19 @@ zh-CN:
86
86
  x_seconds:
87
87
  one: 一秒
88
88
  other: ! '%{count}秒'
89
+ views:
90
+ pagination:
91
+ first: "&laquo; 第一页"
92
+ last: "最后一页 &raquo;"
93
+ previous: "&lsaquo; 上一页"
94
+ next: "下一页 &rsaquo;"
95
+ truncate: "&hellip;"
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}&nbsp;-&nbsp;%{last}</b> 个"
@@ -86,3 +86,19 @@ zh-TW:
86
86
  x_seconds:
87
87
  one: 一秒
88
88
  other: ! '%{count}秒'
89
+ views:
90
+ pagination:
91
+ first: "&laquo; 第一頁"
92
+ last: "最後一頁 &raquo;"
93
+ previous: "&lsaquo; 上一頁"
94
+ next: "下一頁 &rsaquo;"
95
+ truncate: "&hellip;"
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}&nbsp;-&nbsp;%{last}</b> 筆"
@@ -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
@@ -1,5 +1,6 @@
1
1
  require 'casino'
2
2
  require 'casino/inflections'
3
+ require 'yaml'
3
4
 
4
5
  module CASino
5
6
  class Engine < Rails::Engine
@@ -1,3 +1,3 @@
1
1
  module CASino
2
- VERSION = '4.0.3'
2
+ VERSION = '4.1.0'
3
3
  end
@@ -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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options.merge(renew: 'true')
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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(:params) { { lt: login_ticket.ticket }}
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
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, request_options
717
+ get :destroy_others, params
665
718
  response.should redirect_to(url)
666
719
  end
667
720
  end