Skip to content

Commit fb46721

Browse files
committed
implements passwordless login
disables omniauth due to conflicts with passwordless stuff refs: #198118
1 parent 1d148f2 commit fb46721

File tree

14 files changed

+174
-25
lines changed

14 files changed

+174
-25
lines changed

Diff for: Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ gem 'rails-i18n', '~> 4.0.0'
3939
# as authentification framework
4040
gem 'devise', '>= 4.8.0'
4141
gem 'devise_ichain_authenticatable'
42+
gem 'devise-passwordless'
4243
# prevent bot registrations
4344
gem "recaptcha", require: "recaptcha/rails"
4445

Diff for: Gemfile.lock

+10-6
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,9 @@ GEM
239239
railties (>= 4.1.0)
240240
responders
241241
warden (~> 1.2.3)
242+
devise-passwordless (1.0.3)
243+
devise
244+
globalid
242245
devise_ichain_authenticatable (0.3.1)
243246
devise (>= 2.2)
244247
diff-lcs (1.2.5)
@@ -327,7 +330,7 @@ GEM
327330
haml (>= 4.0.6, < 6.0)
328331
html2haml (>= 1.0.1)
329332
railties (>= 4.0.1)
330-
hashie (4.1.0)
333+
hashie (5.0.0)
331334
hightop (0.2.2)
332335
activesupport (>= 4.2)
333336
html2haml (2.2.0)
@@ -365,7 +368,7 @@ GEM
365368
json (2.5.1)
366369
json-schema (2.5.0)
367370
addressable (~> 2.3)
368-
jwt (2.2.3)
371+
jwt (2.7.0)
369372
launchy (2.4.2)
370373
addressable (~> 2.3)
371374
leaflet-rails (0.7.4)
@@ -444,13 +447,13 @@ GEM
444447
oauth2 (~> 1.1)
445448
omniauth (~> 2.0)
446449
omniauth-oauth2 (~> 1.7.1)
447-
omniauth-oauth2 (1.7.1)
448-
oauth2 (~> 1.4)
450+
omniauth-oauth2 (1.7.3)
451+
oauth2 (>= 1.4, < 3)
449452
omniauth (>= 1.9, < 3)
450453
omniauth-openid (2.0.1)
451454
omniauth (>= 1.0, < 3.0)
452455
rack-openid (~> 1.4.0)
453-
omniauth-rails_csrf_protection (1.0.0)
456+
omniauth-rails_csrf_protection (1.0.1)
454457
actionpack (>= 4.2)
455458
omniauth (~> 2.0)
456459
open4 (1.3.4)
@@ -499,7 +502,7 @@ GEM
499502
rack-openid (1.4.2)
500503
rack (>= 1.1.0)
501504
ruby-openid (>= 2.1.8)
502-
rack-protection (2.1.0)
505+
rack-protection (2.2.4)
503506
rack
504507
rack-test (0.6.3)
505508
rack (>= 1.0)
@@ -825,6 +828,7 @@ DEPENDENCIES
825828
database_cleaner
826829
delayed_job_active_record
827830
devise (>= 4.8.0)
831+
devise-passwordless
828832
devise_ichain_authenticatable
829833
dotenv-rails
830834
exception_notification

Diff for: app/assets/stylesheets/newsite.css.scss

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
@import "bootstrap/variables";
2+
@import "bootstrap/mixins";
3+
14
$light_background: #F3F3F3;
25
$main_color: #001970;
36
$background_color: #111e34;
@@ -306,6 +309,19 @@ a:focus {
306309
height: 63vh;
307310
}
308311

312+
.alert {
313+
&-info {
314+
@include alert-variant(rgba(0, 135, 255, 0.1), rgba($alert-info-border,.2), $color_central_blocks);
315+
.close {
316+
color: white;
317+
opacity: .5;
318+
}
319+
.close:hover {
320+
opacity: 1;
321+
}
322+
}
323+
}
324+
309325
.main-card {
310326
padding: 4vh;
311327
background: -webkit-linear-gradient($background);
@@ -469,13 +485,13 @@ a:focus {
469485

470486
.cta-btn-other {
471487
background-color: $main_color;
472-
color: $button_color;
488+
color: $button_color !important;
473489
width: 100%;
474490
border: 2px solid $main_color;
475491
transition: 0.2s all linear 0s;
476492
&:hover, &:focus{
477493
background-color: transparent;
478-
color: $main_color;
494+
color: $main_color !important;
479495
transition: 0.2s all ease-in 0s;
480496
}
481497
}

Diff for: app/controllers/application_controller.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def store_location
2929
request.path != '/accounts/password/edit' &&
3030
request.path != '/accounts/confirmation' &&
3131
request.path != '/accounts/sign_out' &&
32+
request.path != '/accounts/magic_link' &&
3233
request.path != '/users/ichain_registration/ichain_sign_up' &&
3334
!request.path.starts_with?(Devise.ichain_base_url) &&
3435
!request.xhr?) # don't store ajax calls
@@ -48,7 +49,7 @@ def after_sign_in_path_for(_resource)
4849
end
4950

5051
def get_conferences
51-
@conferences =Conference.all
52+
@conferences = Conference.all
5253
end
5354

5455
def current_ability

Diff for: app/models/user.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ def by_conference(conference)
3939
if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
4040
devise_modules += [ :ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: [] ]
4141
else
42-
devise_modules += [:database_authenticatable, :registerable,
42+
devise_modules += [:database_authenticatable, :registerable, :magic_link_authenticatable,
4343
:recoverable, :rememberable, :trackable, :validatable, :confirmable,
44-
:omniauthable, omniauth_providers: [:suse, :google, :facebook, :github] ]
44+
]
4545
end
4646

4747
devise(*devise_modules)

Diff for: app/views/devise/mailer/magic_link.html.erb

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<p>Hello <%= @resource.email %>!</p>
2+
3+
<p>You can login to Postgres Conference using the link below:</p>
4+
5+
<p><%= link_to "Log in to my account", magic_link_url(@resource, @scope_name => {login: @resource.email, token: @token, remember_me: @remember_me}) %></p>
6+
7+
<p>Note that the link will expire in <%= Devise.passwordless_login_within.seconds/60 %> minutes.</p>

Diff for: app/views/devise/registrations/edit.html.haml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
%h4
3131
To add an openID with a different email address to your account, sign in with your
3232
openID while logged in to PostgresConf
33-
- if User.omniauth_providers.present?
33+
- if User.try(:omniauth_providers).present?
3434
#openidlinks
3535
= render 'devise/shared/openid_links'
3636
= f.inputs name: 'Confirmation' do

Diff for: app/views/layouts/_navigation.html.haml

+39-1
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,41 @@
8989
= password_field_tag 'password', nil, id: 'user_ichain_password_dd', placeholder: 'Password'
9090
%button.btn.btn-success.btn-block Sign in
9191
- else
92-
= form_tag new_user_session_path do
92+
= form_tag new_user_session_path, id: 'login_form', style: 'display: none' do
9393
= text_field_tag 'user[login]', nil, id: 'user_login_dd', placeholder: 'E-Mail'
9494
= password_field_tag 'user[password]', nil, id: 'user_password_dd', placeholder: 'Password'
9595
%p.text-right
9696
%small
9797
Remember me
9898
= check_box_tag 'user[remember_me]'
9999
%button.btn.btn-success.btn-block Sign in
100+
.divider
101+
%h6.text-center
102+
= link_to 'Sign in with email', '#', id: 'passwordless_toggle'
103+
104+
- unless omniauth_configured.empty?
105+
.divider
106+
%h6.text-center
107+
or
108+
= render 'devise/shared/openid_links'
109+
%div.dropdown-footer.clearfix
110+
%a.small.btn.btn-xs.btn-default.pull-right{"data-toggle" => "collapse", "data-target" => "#navbar-devise-help"}
111+
Need Help?
112+
#navbar-devise-help.collapse
113+
= render 'devise/shared/links'
114+
%li.hidden-lg
115+
= link_to('Sign In', new_user_session_path)
116+
117+
= form_tag new_passwordless_user_session_path, id: 'passwordless_login_form' do
118+
= text_field_tag 'passwordless_user[email]', nil, id: 'user_login_dd', placeholder: 'E-Mail'
119+
%p.text-right
120+
%small
121+
Remember me
122+
= check_box_tag 'user[remember_me]'
123+
%button.btn.btn-success.btn-block Sign in
124+
.divider
125+
%h6.text-center
126+
= link_to 'Sign in with password', '#', id: 'password_toggle'
100127
- unless omniauth_configured.empty?
101128
.divider
102129
%h6.text-center
@@ -195,4 +222,15 @@
195222
$('.navbar-collapse').scrollTop(9000)
196223
}
197224
})
225+
$('#password_toggle').on('click', function(e) {
226+
e.stopPropagation()
227+
$('#login_form').show()
228+
$('#passwordless_login_form').hide()
229+
});
230+
231+
$('#passwordless_toggle').on('click', function(e) {
232+
e.stopPropagation()
233+
$('#login_form').hide()
234+
$('#passwordless_login_form').show()
235+
});
198236
})

Diff for: app/views/layouts/websitenew.html.haml

+21-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
PgConf
1818
- else
1919
Postgres Conference
20+
2021
.container-fluid
2122
.row
2223
- @meetups = Refinery::Meetups::Meetup.upcoming(10)
@@ -27,6 +28,13 @@
2728
- @top_card = @digital_events.first || @current.second
2829
- @bottom_card = @meetups.first || @current.third
2930
.col-md-10.col-md-offset-1
31+
- flash.each do |type, message|
32+
%div{:class=>"alert alert-dismissable #{bootstrap_class_for(type)}", :id=>"flash"}
33+
.button.close{"data-dismiss" => "alert", "aria-hidden"=>"true"}
34+
&times;
35+
%p
36+
= message
37+
3038
.row.wrapper-main-cards
3139
.col-md-7.col-sm-12.h-100
3240
= render partial: "/refinery/conference_card_main", locals: { conference: @main_conference } if @main_conference
@@ -136,4 +144,16 @@
136144
let selector = $(event.target).data('scrolldown-target')
137145
//we cant scroll the invisible element immediately, the timeout is to ensure the element is visible and DOM is recalculated
138146
setTimeout(function(){$(selector)[0].scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"})},10);
139-
})
147+
})
148+
149+
$('#password_toggle').on('click', function(e) {
150+
e.stopPropagation()
151+
$('#login_form').show()
152+
$('#passwordless_login_form').hide()
153+
});
154+
155+
$('#passwordless_toggle').on('click', function(e) {
156+
e.stopPropagation()
157+
$('#login_form').hide()
158+
$('#passwordless_login_form').show()
159+
});

Diff for: app/views/refinery/_header.html.haml

+26-2
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,38 @@
4242
Sign in
4343
%b.caret
4444
.dropdown-menu.sign-in-form
45-
= form_tag main_app.new_user_session_path do
45+
= form_tag main_app.new_user_session_path, id: 'login_form', method: :post, style: 'display: none' do
4646
%h2.text-center Sign in
4747
.form-group
4848
= text_field_tag 'user[login]', nil, id: 'user_login_dd', placeholder: 'E-Mail', class: 'form-control'
4949
.form-group
5050
= password_field_tag 'user[password]', nil, id: 'user_password_dd', placeholder: 'Password', class: 'form-control'
5151
.form-group
52-
= button_to 'Log In', main_app.new_user_session_path, class: 'btn cta-btn-other uppercase bold'
52+
= link_to 'Sign In', '#', class: 'btn cta-btn-other uppercase bold', :onclick => "$('#login_form').submit()"
53+
54+
.form-group.text-center.font-weight-normal
55+
= link_to 'Sign in with email', '#', id: 'passwordless_toggle'
56+
57+
.form-group.text-center.font-weight-normal
58+
Don't have an account?
59+
= link_to 'Register', main_app.new_user_registration_path
60+
.clearfix
61+
%label.pull-left.checkbox-inline
62+
= check_box_tag 'user[remember_me]'
63+
Remember me
64+
%a.pull-right{"aria-expanded" => "true", "id" => "help_link", "data-target" => "#navbar-devise-help", "data-toggle" => "collapse", :href => "#"} Need help?
65+
#navbar-devise-help.collapse{"aria-expanded" => "true"}
66+
= render 'devise/shared/links'
67+
68+
= form_tag main_app.new_passwordless_user_session_path, id: 'passwordless_login_form' do
69+
%h2.text-center Sign in
70+
.form-group
71+
= text_field_tag 'passwordless_user[email]', nil, id: 'passwordless_user_email_dd', placeholder: 'E-Mail', class: 'form-control'
72+
.form-group
73+
= link_to 'Sign In', '#', class: 'btn cta-btn-other uppercase bold', :onclick => "$('#passwordless_login_form').submit()"
74+
75+
.form-group.text-center.font-weight-normal
76+
= link_to 'Sign in with password', '#', id: 'password_toggle'
5377

5478
.form-group.text-center.font-weight-normal
5579
Don't have an account?

Diff for: config/application.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class Application < Rails::Application
3939
config.encoding = 'utf-8'
4040

4141
# Configure sensitive parameters which will be filtered from the log file.
42-
config.filter_parameters += [:password]
42+
config.filter_parameters += [:password, :token]
4343

4444
# Enable escaping HTML in JSON.
4545
config.active_support.escape_html_entities_in_json = true
@@ -69,4 +69,3 @@ class Application < Rails::Application
6969
config.exceptions_app = self.routes
7070
end
7171
end
72-

Diff for: config/initializers/devise.rb

+25
Original file line numberDiff line numberDiff line change
@@ -271,4 +271,29 @@
271271

272272
# In test mode, force the following additional attributes
273273
# config.ichain_force_test_attributes = {:email => "[email protected]"}
274+
275+
# ==> Configuration for :magic_link_authenticatable
276+
277+
# Need to use a custom Devise mailer in order to send magic links.
278+
# If you're already using a custom mailer just have it inherit from
279+
# Devise::Passwordless::Mailer instead of Devise::Mailer
280+
config.mailer = "Devise::Passwordless::Mailer"
281+
282+
# Which algorithm to use for tokenizing magic links. See README for descriptions
283+
config.passwordless_tokenizer = "SignedGlobalIDTokenizer"
284+
285+
# Time period after a magic login link is sent out that it will be valid for.
286+
# config.passwordless_login_within = 20.minutes
287+
288+
# The secret key used to generate passwordless login tokens. The default value
289+
# is nil, which means defer to Devise's `secret_key` config value. Changing this
290+
# key will render invalid all existing passwordless login tokens. You can
291+
# generate your own secret value with e.g. `rake secret`
292+
# config.passwordless_secret_key = nil
293+
294+
# When using the :trackable module and MessageEncryptorTokenizer, set to true to
295+
# consider magic link tokens generated before the user's current sign in time to
296+
# be expired. In other words, each time you sign in, all existing magic links
297+
# will be considered invalid.
298+
# config.passwordless_expire_old_tokens_on_sign_in = false
274299
end

Diff for: config/locales/devise.en.yml

+16-6
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,19 @@ en:
5050
success: 'Successfully authenticated from %{kind} account.'
5151
failure: 'Could not authenticate you from %{kind} because "%{reason}".'
5252
mailer:
53-
confirmation_instructions:
54-
subject: 'Confirmation instructions'
55-
reset_password_instructions:
56-
subject: 'Reset password instructions'
57-
unlock_instructions:
58-
subject: 'Unlock Instructions'
53+
magic_link:
54+
user_subject: "Here's your USER magic login link ✨"
55+
admin_subject: "Here's your ADMIN magic login link ✨"
56+
subject: "Here's your magic login link ✨"
57+
passwordless:
58+
user:
59+
not_found_in_database: "Could not find a USER for that email address"
60+
magic_link_sent: "A USER login link has been sent to your email address. Please follow the link to log in to your account."
61+
magic_link_sent_paranoid: "If your USER account exists, you will receive an email with a login link. Please follow the link to log in to your account."
62+
admin:
63+
not_found_in_database: "Could not find an ADMIN for that email address"
64+
magic_link_sent: "An ADMIN login link has been sent to your email address. Please follow the link to log in to your account."
65+
magic_link_sent_paranoid: "If your ADMIN account exists, you will receive an email with a login link. Please follow the link to log in to your account."
66+
not_found_in_database: "Could not find a user for that email address"
67+
magic_link_sent: "A login link has been sent to your email address. Please follow the link to log in to your account."
68+
magic_link_sent_paranoid: "If your account exists, you will receive an email with a login link. Please follow the link to log in to your account."

Diff for: config/routes.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
devise_for :users,
77
controllers: {
88
registrations: :registrations, confirmations: :confirmations,
9-
omniauth_callbacks: 'users/omniauth_callbacks' },
9+
},
1010
path: 'accounts'
11+
namespace "passwordless" do
12+
devise_for :users,
13+
controllers: { sessions: "devise/passwordless/sessions" }
14+
end
1115
end
1216

1317
# Use letter_opener_web to open mails in browser (e.g. necessary for Vagrant)

0 commit comments

Comments
 (0)