commit
e7e04b46d7
|
@ -228,6 +228,7 @@ SMTP_FROM_ADDRESS=notifications@${APP_NAME}.nanoapp.io
|
||||||
# CAS_LOCATION_KEY='location'
|
# CAS_LOCATION_KEY='location'
|
||||||
# CAS_IMAGE_KEY='image'
|
# CAS_IMAGE_KEY='image'
|
||||||
# CAS_PHONE_KEY='phone'
|
# CAS_PHONE_KEY='phone'
|
||||||
|
# CAS_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true
|
||||||
|
|
||||||
# Optional SAML authentication (cf. omniauth-saml)
|
# Optional SAML authentication (cf. omniauth-saml)
|
||||||
# SAML_ENABLED=true
|
# SAML_ENABLED=true
|
||||||
|
|
116
Gemfile.lock
116
Gemfile.lock
|
@ -1,40 +1,40 @@
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.1.4)
|
actioncable (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.4)
|
actionmailbox (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activejob (= 6.1.4)
|
activejob (= 6.1.4.1)
|
||||||
activerecord (= 6.1.4)
|
activerecord (= 6.1.4.1)
|
||||||
activestorage (= 6.1.4)
|
activestorage (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.4)
|
actionmailer (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
actionview (= 6.1.4)
|
actionview (= 6.1.4.1)
|
||||||
activejob (= 6.1.4)
|
activejob (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.1.4)
|
actionpack (6.1.4.1)
|
||||||
actionview (= 6.1.4)
|
actionview (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
rack (~> 2.0, >= 2.0.9)
|
rack (~> 2.0, >= 2.0.9)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.1.4)
|
actiontext (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activerecord (= 6.1.4)
|
activerecord (= 6.1.4.1)
|
||||||
activestorage (= 6.1.4)
|
activestorage (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.4)
|
actionview (6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
|
@ -45,22 +45,22 @@ GEM
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
active_record_query_trace (1.8)
|
active_record_query_trace (1.8)
|
||||||
activejob (6.1.4)
|
activejob (6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.4)
|
activemodel (6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
activerecord (6.1.4)
|
activerecord (6.1.4.1)
|
||||||
activemodel (= 6.1.4)
|
activemodel (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
activestorage (6.1.4)
|
activestorage (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activejob (= 6.1.4)
|
activejob (= 6.1.4.1)
|
||||||
activerecord (= 6.1.4)
|
activerecord (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
marcel (~> 1.0.0)
|
marcel (~> 1.0.0)
|
||||||
mini_mime (>= 1.1.0)
|
mini_mime (>= 1.1.0)
|
||||||
activesupport (6.1.4)
|
activesupport (6.1.4.1)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
|
@ -243,8 +243,8 @@ GEM
|
||||||
fuubar (2.5.1)
|
fuubar (2.5.1)
|
||||||
rspec-core (~> 3.0)
|
rspec-core (~> 3.0)
|
||||||
ruby-progressbar (~> 1.4)
|
ruby-progressbar (~> 1.4)
|
||||||
globalid (0.4.2)
|
globalid (0.5.2)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 5.0)
|
||||||
hamlit (2.13.0)
|
hamlit (2.13.0)
|
||||||
temple (>= 0.8.2)
|
temple (>= 0.8.2)
|
||||||
thor
|
thor
|
||||||
|
@ -353,7 +353,7 @@ GEM
|
||||||
mimemagic (0.3.10)
|
mimemagic (0.3.10)
|
||||||
nokogiri (~> 1)
|
nokogiri (~> 1)
|
||||||
rake
|
rake
|
||||||
mini_mime (1.1.0)
|
mini_mime (1.1.1)
|
||||||
mini_portile2 (2.6.1)
|
mini_portile2 (2.6.1)
|
||||||
minitest (5.14.4)
|
minitest (5.14.4)
|
||||||
msgpack (1.4.2)
|
msgpack (1.4.2)
|
||||||
|
@ -363,7 +363,7 @@ GEM
|
||||||
net-scp (3.0.0)
|
net-scp (3.0.0)
|
||||||
net-ssh (>= 2.6.5, < 7.0.0)
|
net-ssh (>= 2.6.5, < 7.0.0)
|
||||||
net-ssh (6.1.0)
|
net-ssh (6.1.0)
|
||||||
nio4r (2.5.7)
|
nio4r (2.5.8)
|
||||||
nokogiri (1.12.3)
|
nokogiri (1.12.3)
|
||||||
mini_portile2 (~> 2.6.1)
|
mini_portile2 (~> 2.6.1)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
|
@ -441,20 +441,20 @@ GEM
|
||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.1.4)
|
rails (6.1.4.1)
|
||||||
actioncable (= 6.1.4)
|
actioncable (= 6.1.4.1)
|
||||||
actionmailbox (= 6.1.4)
|
actionmailbox (= 6.1.4.1)
|
||||||
actionmailer (= 6.1.4)
|
actionmailer (= 6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
actiontext (= 6.1.4)
|
actiontext (= 6.1.4.1)
|
||||||
actionview (= 6.1.4)
|
actionview (= 6.1.4.1)
|
||||||
activejob (= 6.1.4)
|
activejob (= 6.1.4.1)
|
||||||
activemodel (= 6.1.4)
|
activemodel (= 6.1.4.1)
|
||||||
activerecord (= 6.1.4)
|
activerecord (= 6.1.4.1)
|
||||||
activestorage (= 6.1.4)
|
activestorage (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.4)
|
railties (= 6.1.4.1)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
|
@ -463,16 +463,16 @@ GEM
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.0.3)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.3.0)
|
rails-html-sanitizer (1.4.1)
|
||||||
loofah (~> 2.3)
|
loofah (~> 2.3)
|
||||||
rails-i18n (6.0.0)
|
rails-i18n (6.0.0)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 6.0.0, < 7)
|
railties (>= 6.0.0, < 7)
|
||||||
rails-settings-cached (0.6.6)
|
rails-settings-cached (0.6.6)
|
||||||
rails (>= 4.2.0)
|
rails (>= 4.2.0)
|
||||||
railties (6.1.4)
|
railties (6.1.4.1)
|
||||||
actionpack (= 6.1.4)
|
actionpack (= 6.1.4.1)
|
||||||
activesupport (= 6.1.4)
|
activesupport (= 6.1.4.1)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.13)
|
rake (>= 0.13)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||||
|
|
||||||
if @user.persisted?
|
if @user.persisted?
|
||||||
LoginActivity.create(
|
LoginActivity.create(
|
||||||
user: user,
|
user: @user,
|
||||||
success: true,
|
success: true,
|
||||||
authentication_method: :omniauth,
|
authentication_method: :omniauth,
|
||||||
provider: provider,
|
provider: provider,
|
||||||
|
|
|
@ -47,7 +47,10 @@ class Auth::SessionsController < Devise::SessionsController
|
||||||
user = find_user
|
user = find_user
|
||||||
|
|
||||||
if user&.webauthn_enabled?
|
if user&.webauthn_enabled?
|
||||||
options_for_get = WebAuthn::Credential.options_for_get(allow: user.webauthn_credentials.pluck(:external_id))
|
options_for_get = WebAuthn::Credential.options_for_get(
|
||||||
|
allow: user.webauthn_credentials.pluck(:external_id),
|
||||||
|
user_verification: 'discouraged'
|
||||||
|
)
|
||||||
|
|
||||||
session[:webauthn_challenge] = options_for_get.challenge
|
session[:webauthn_challenge] = options_for_get.challenge
|
||||||
|
|
||||||
|
@ -60,15 +63,19 @@ class Auth::SessionsController < Devise::SessionsController
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def find_user
|
def find_user
|
||||||
if session[:attempt_user_id]
|
if user_params[:email].present?
|
||||||
|
find_user_from_params
|
||||||
|
elsif session[:attempt_user_id]
|
||||||
User.find_by(id: session[:attempt_user_id])
|
User.find_by(id: session[:attempt_user_id])
|
||||||
else
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_user_from_params
|
||||||
user = User.authenticate_with_ldap(user_params) if Devise.ldap_authentication
|
user = User.authenticate_with_ldap(user_params) if Devise.ldap_authentication
|
||||||
user ||= User.authenticate_with_pam(user_params) if Devise.pam_authentication
|
user ||= User.authenticate_with_pam(user_params) if Devise.pam_authentication
|
||||||
user ||= User.find_for_authentication(email: user_params[:email])
|
user ||= User.find_for_authentication(email: user_params[:email])
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:email, :password, :otp_attempt, :sign_in_token_attempt, credential: {})
|
params.require(:user).permit(:email, :password, :otp_attempt, :sign_in_token_attempt, credential: {})
|
||||||
|
|
|
@ -16,14 +16,18 @@ module SignInTokenAuthenticationConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate_with_sign_in_token
|
def authenticate_with_sign_in_token
|
||||||
user = self.resource = find_user
|
if user_params[:email].present?
|
||||||
|
user = self.resource = find_user_from_params
|
||||||
|
prompt_for_sign_in_token(user) if user&.external_or_valid_password?(user_params[:password])
|
||||||
|
elsif session[:attempt_user_id]
|
||||||
|
user = self.resource = User.find_by(id: session[:attempt_user_id])
|
||||||
|
return if user.nil?
|
||||||
|
|
||||||
if user.present? && session[:attempt_user_id].present? && session[:attempt_user_updated_at] != user.updated_at.to_s
|
if session[:attempt_user_updated_at] != user.updated_at.to_s
|
||||||
restart_session
|
restart_session
|
||||||
elsif user_params.key?(:sign_in_token_attempt) && session[:attempt_user_id]
|
elsif user_params.key?(:sign_in_token_attempt)
|
||||||
authenticate_with_sign_in_token_attempt(user)
|
authenticate_with_sign_in_token_attempt(user)
|
||||||
elsif user.present? && user.external_or_valid_password?(user_params[:password])
|
end
|
||||||
prompt_for_sign_in_token(user)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -35,16 +35,20 @@ module TwoFactorAuthenticationConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate_with_two_factor
|
def authenticate_with_two_factor
|
||||||
user = self.resource = find_user
|
if user_params[:email].present?
|
||||||
|
user = self.resource = find_user_from_params
|
||||||
|
prompt_for_two_factor(user) if user&.external_or_valid_password?(user_params[:password])
|
||||||
|
elsif session[:attempt_user_id]
|
||||||
|
user = self.resource = User.find_by(id: session[:attempt_user_id])
|
||||||
|
return if user.nil?
|
||||||
|
|
||||||
if user.present? && session[:attempt_user_id].present? && session[:attempt_user_updated_at] != user.updated_at.to_s
|
if session[:attempt_user_updated_at] != user.updated_at.to_s
|
||||||
restart_session
|
restart_session
|
||||||
elsif user.webauthn_enabled? && user_params.key?(:credential) && session[:attempt_user_id]
|
elsif user.webauthn_enabled? && user_params.key?(:credential)
|
||||||
authenticate_with_two_factor_via_webauthn(user)
|
authenticate_with_two_factor_via_webauthn(user)
|
||||||
elsif user_params.key?(:otp_attempt) && session[:attempt_user_id]
|
elsif user_params.key?(:otp_attempt)
|
||||||
authenticate_with_two_factor_via_otp(user)
|
authenticate_with_two_factor_via_otp(user)
|
||||||
elsif user.present? && user.external_or_valid_password?(user_params[:password])
|
end
|
||||||
prompt_for_two_factor(user)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ module Settings
|
||||||
display_name: current_user.account.username,
|
display_name: current_user.account.username,
|
||||||
id: current_user.webauthn_id,
|
id: current_user.webauthn_id,
|
||||||
},
|
},
|
||||||
exclude: current_user.webauthn_credentials.pluck(:external_id)
|
exclude: current_user.webauthn_credentials.pluck(:external_id),
|
||||||
|
authenticator_selection: { user_verification: 'discouraged' }
|
||||||
)
|
)
|
||||||
|
|
||||||
session[:webauthn_challenge] = options_for_create.challenge
|
session[:webauthn_challenge] = options_for_create.challenge
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import api, { getLinks } from 'flavours/glitch/util/api';
|
import api, { getLinks } from 'flavours/glitch/util/api';
|
||||||
import IntlMessageFormat from 'intl-messageformat';
|
import IntlMessageFormat from 'intl-messageformat';
|
||||||
import { fetchRelationships } from './accounts';
|
import { fetchFollowRequests, fetchRelationships } from './accounts';
|
||||||
import {
|
import {
|
||||||
importFetchedAccount,
|
importFetchedAccount,
|
||||||
importFetchedAccounts,
|
importFetchedAccounts,
|
||||||
|
@ -90,6 +90,10 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
||||||
filtered = regex && regex.test(searchIndex);
|
filtered = regex && regex.test(searchIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (['follow_request'].includes(notification.type)) {
|
||||||
|
dispatch(fetchFollowRequests());
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(submitMarkers());
|
dispatch(submitMarkers());
|
||||||
|
|
||||||
if (showInColumn) {
|
if (showInColumn) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import api, { getLinks } from '../api';
|
import api, { getLinks } from '../api';
|
||||||
import IntlMessageFormat from 'intl-messageformat';
|
import IntlMessageFormat from 'intl-messageformat';
|
||||||
import { fetchRelationships } from './accounts';
|
import { fetchFollowRequests, fetchRelationships } from './accounts';
|
||||||
import {
|
import {
|
||||||
importFetchedAccount,
|
importFetchedAccount,
|
||||||
importFetchedAccounts,
|
importFetchedAccounts,
|
||||||
|
@ -78,6 +78,10 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
||||||
filtered = regex && regex.test(searchIndex);
|
filtered = regex && regex.test(searchIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (['follow_request'].includes(notification.type)) {
|
||||||
|
dispatch(fetchFollowRequests());
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(submitMarkers());
|
dispatch(submitMarkers());
|
||||||
|
|
||||||
if (showInColumn) {
|
if (showInColumn) {
|
||||||
|
|
|
@ -30,6 +30,8 @@ Devise.setup do |config|
|
||||||
cas_options[:location_key] = ENV['CAS_LOCATION_KEY'] || 'location'
|
cas_options[:location_key] = ENV['CAS_LOCATION_KEY'] || 'location'
|
||||||
cas_options[:image_key] = ENV['CAS_IMAGE_KEY'] || 'image'
|
cas_options[:image_key] = ENV['CAS_IMAGE_KEY'] || 'image'
|
||||||
cas_options[:phone_key] = ENV['CAS_PHONE_KEY'] || 'phone'
|
cas_options[:phone_key] = ENV['CAS_PHONE_KEY'] || 'phone'
|
||||||
|
cas_options[:security] = {}
|
||||||
|
cas_options[:security][:assume_email_is_verified] = ENV['CAS_SECURITY_ASSUME_EMAIL_IS_VERIFIED'] == 'true'
|
||||||
config.omniauth :cas, cas_options
|
config.omniauth :cas, cas_options
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
"@babel/core": "^7.15.0",
|
"@babel/core": "^7.15.0",
|
||||||
"@babel/plugin-proposal-decorators": "^7.14.5",
|
"@babel/plugin-proposal-decorators": "^7.14.5",
|
||||||
"@babel/plugin-transform-react-inline-elements": "^7.14.5",
|
"@babel/plugin-transform-react-inline-elements": "^7.14.5",
|
||||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
"@babel/plugin-transform-runtime": "^7.15.0",
|
||||||
"@babel/preset-env": "^7.15.0",
|
"@babel/preset-env": "^7.15.0",
|
||||||
"@babel/preset-react": "^7.14.5",
|
"@babel/preset-react": "^7.14.5",
|
||||||
"@babel/runtime": "^7.15.3",
|
"@babel/runtime": "^7.15.3",
|
||||||
|
@ -171,7 +171,7 @@
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-merge": "^5.8.0",
|
"webpack-merge": "^5.8.0",
|
||||||
"wicg-inert": "^3.1.1",
|
"wicg-inert": "^3.1.1",
|
||||||
"ws": "^8.1.0"
|
"ws": "^8.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
|
@ -179,7 +179,7 @@
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-jest": "^27.0.6",
|
"babel-jest": "^27.0.6",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-plugin-import": "~2.24.0",
|
"eslint-plugin-import": "~2.24.1",
|
||||||
"eslint-plugin-jsx-a11y": "~6.4.1",
|
"eslint-plugin-jsx-a11y": "~6.4.1",
|
||||||
"eslint-plugin-promise": "~5.1.0",
|
"eslint-plugin-promise": "~5.1.0",
|
||||||
"eslint-plugin-react": "~7.24.0",
|
"eslint-plugin-react": "~7.24.0",
|
||||||
|
|
|
@ -206,6 +206,38 @@ RSpec.describe Auth::SessionsController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'using email and password after an unfinished log-in attempt to a 2FA-protected account' do
|
||||||
|
let!(:other_user) do
|
||||||
|
Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
post :create, params: { user: { email: other_user.email, password: other_user.password } }
|
||||||
|
post :create, params: { user: { email: user.email, password: user.password } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders two factor authentication page' do
|
||||||
|
expect(controller).to render_template("two_factor")
|
||||||
|
expect(controller).to render_template(partial: "_otp_authentication_form")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'using email and password after an unfinished log-in attempt with a sign-in token challenge' do
|
||||||
|
let!(:other_user) do
|
||||||
|
Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: false, current_sign_in_at: 1.month.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
post :create, params: { user: { email: other_user.email, password: other_user.password } }
|
||||||
|
post :create, params: { user: { email: user.email, password: user.password } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders two factor authentication page' do
|
||||||
|
expect(controller).to render_template("two_factor")
|
||||||
|
expect(controller).to render_template(partial: "_otp_authentication_form")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'using upcase email and password' do
|
context 'using upcase email and password' do
|
||||||
before do
|
before do
|
||||||
post :create, params: { user: { email: user.email.upcase, password: user.password } }
|
post :create, params: { user: { email: user.email.upcase, password: user.password } }
|
||||||
|
@ -231,6 +263,21 @@ RSpec.describe Auth::SessionsController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'using a valid OTP, attempting to leverage previous half-login to bypass password auth' do
|
||||||
|
let!(:other_user) do
|
||||||
|
Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: false, current_sign_in_at: 1.month.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
post :create, params: { user: { email: other_user.email, password: other_user.password } }
|
||||||
|
post :create, params: { user: { email: user.email, otp_attempt: user.current_otp } }, session: { attempt_user_updated_at: user.updated_at.to_s }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't log the user in" do
|
||||||
|
expect(controller.current_user).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when the server has an decryption error' do
|
context 'when the server has an decryption error' do
|
||||||
before do
|
before do
|
||||||
allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError)
|
allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError)
|
||||||
|
@ -380,6 +427,52 @@ RSpec.describe Auth::SessionsController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'using email and password after an unfinished log-in attempt to a 2FA-protected account' do
|
||||||
|
let!(:other_user) do
|
||||||
|
Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
post :create, params: { user: { email: other_user.email, password: other_user.password } }
|
||||||
|
post :create, params: { user: { email: user.email, password: user.password } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders sign in token authentication page' do
|
||||||
|
expect(controller).to render_template("sign_in_token")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'generates sign in token' do
|
||||||
|
expect(user.reload.sign_in_token).to_not be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends sign in token e-mail' do
|
||||||
|
expect(UserMailer).to have_received(:sign_in_token)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'using email and password after an unfinished log-in attempt with a sign-in token challenge' do
|
||||||
|
let!(:other_user) do
|
||||||
|
Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: false, current_sign_in_at: 1.month.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
post :create, params: { user: { email: other_user.email, password: other_user.password } }
|
||||||
|
post :create, params: { user: { email: user.email, password: user.password } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders sign in token authentication page' do
|
||||||
|
expect(controller).to render_template("sign_in_token")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'generates sign in token' do
|
||||||
|
expect(user.reload.sign_in_token).to_not be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends sign in token e-mail' do
|
||||||
|
expect(UserMailer).to have_received(:sign_in_token).with(user, any_args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'using a valid sign in token' do
|
context 'using a valid sign in token' do
|
||||||
before do
|
before do
|
||||||
user.generate_sign_in_token && user.save
|
user.generate_sign_in_token && user.save
|
||||||
|
@ -395,6 +488,22 @@ RSpec.describe Auth::SessionsController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'using a valid sign in token, attempting to leverage previous half-login to bypass password auth' do
|
||||||
|
let!(:other_user) do
|
||||||
|
Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: false, current_sign_in_at: 1.month.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
user.generate_sign_in_token && user.save
|
||||||
|
post :create, params: { user: { email: other_user.email, password: other_user.password } }
|
||||||
|
post :create, params: { user: { email: user.email, sign_in_token_attempt: user.sign_in_token } }, session: { attempt_user_updated_at: user.updated_at.to_s }
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't log the user in" do
|
||||||
|
expect(controller.current_user).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'using an invalid sign in token' do
|
context 'using an invalid sign in token' do
|
||||||
before do
|
before do
|
||||||
post :create, params: { user: { sign_in_token_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
|
post :create, params: { user: { sign_in_token_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
|
||||||
|
|
71
yarn.lock
71
yarn.lock
|
@ -817,10 +817,10 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-plugin-utils" "^7.14.5"
|
"@babel/helper-plugin-utils" "^7.14.5"
|
||||||
|
|
||||||
"@babel/plugin-transform-runtime@^7.14.5":
|
"@babel/plugin-transform-runtime@^7.15.0":
|
||||||
version "7.14.5"
|
version "7.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.14.5.tgz#30491dad49c6059f8f8fa5ee8896a0089e987523"
|
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz#d3aa650d11678ca76ce294071fda53d7804183b3"
|
||||||
integrity sha512-fPMBhh1AV8ZyneiCIA+wYYUH1arzlXR1UMcApjvchDhfKxhy2r2lReJv8uHEyihi4IFIGlr1Pdx7S5fkESDQsg==
|
integrity sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-module-imports" "^7.14.5"
|
"@babel/helper-module-imports" "^7.14.5"
|
||||||
"@babel/helper-plugin-utils" "^7.14.5"
|
"@babel/helper-plugin-utils" "^7.14.5"
|
||||||
|
@ -1581,11 +1581,6 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
|
||||||
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
|
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
|
||||||
|
|
||||||
"@types/json5@^0.0.29":
|
|
||||||
version "0.0.29"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
|
||||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
|
||||||
|
|
||||||
"@types/minimatch@*":
|
"@types/minimatch@*":
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
|
@ -4343,10 +4338,10 @@ escope@^3.6.0:
|
||||||
esrecurse "^4.1.0"
|
esrecurse "^4.1.0"
|
||||||
estraverse "^4.1.1"
|
estraverse "^4.1.1"
|
||||||
|
|
||||||
eslint-import-resolver-node@^0.3.5:
|
eslint-import-resolver-node@^0.3.6:
|
||||||
version "0.3.5"
|
version "0.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.5.tgz#939bbb0f74e179e757ca87f7a4a890dabed18ac4"
|
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd"
|
||||||
integrity sha512-XMoPKjSpXbkeJ7ZZ9icLnJMTY5Mc1kZbCakHquaFsXPpyWOwK0TK6CODO+0ca54UoM9LKOxyUNnoVZRl8TeaAg==
|
integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "^3.2.7"
|
debug "^3.2.7"
|
||||||
resolve "^1.20.0"
|
resolve "^1.20.0"
|
||||||
|
@ -4359,26 +4354,26 @@ eslint-module-utils@^2.6.2:
|
||||||
debug "^3.2.7"
|
debug "^3.2.7"
|
||||||
pkg-dir "^2.0.0"
|
pkg-dir "^2.0.0"
|
||||||
|
|
||||||
eslint-plugin-import@~2.24.0:
|
eslint-plugin-import@~2.24.1:
|
||||||
version "2.24.0"
|
version "2.24.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.0.tgz#697ffd263e24da5e84e03b282f5fb62251777177"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.1.tgz#64aba8b567a1ba9921d5465586e86c491b8e2135"
|
||||||
integrity sha512-Kc6xqT9hiYi2cgybOc0I2vC9OgAYga5o/rAFinam/yF/t5uBqxQbauNPMC6fgb640T/89P0gFoO27FOilJ/Cqg==
|
integrity sha512-KSFWhNxPH8OGJwpRJJs+Z7I0a13E2iFQZJIvSnCu6KUs4qmgAm3xN9GYBCSoiGWmwA7gERZPXqYQjcoCROnYhQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
array-includes "^3.1.3"
|
array-includes "^3.1.3"
|
||||||
array.prototype.flat "^1.2.4"
|
array.prototype.flat "^1.2.4"
|
||||||
debug "^2.6.9"
|
debug "^2.6.9"
|
||||||
doctrine "^2.1.0"
|
doctrine "^2.1.0"
|
||||||
eslint-import-resolver-node "^0.3.5"
|
eslint-import-resolver-node "^0.3.6"
|
||||||
eslint-module-utils "^2.6.2"
|
eslint-module-utils "^2.6.2"
|
||||||
find-up "^2.0.0"
|
find-up "^2.0.0"
|
||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
is-core-module "^2.4.0"
|
is-core-module "^2.6.0"
|
||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
object.values "^1.1.3"
|
object.values "^1.1.4"
|
||||||
pkg-up "^2.0.0"
|
pkg-up "^2.0.0"
|
||||||
read-pkg-up "^3.0.0"
|
read-pkg-up "^3.0.0"
|
||||||
resolve "^1.20.0"
|
resolve "^1.20.0"
|
||||||
tsconfig-paths "^3.9.0"
|
tsconfig-paths "^3.10.1"
|
||||||
|
|
||||||
eslint-plugin-jsx-a11y@~6.4.1:
|
eslint-plugin-jsx-a11y@~6.4.1:
|
||||||
version "6.4.1"
|
version "6.4.1"
|
||||||
|
@ -5976,10 +5971,10 @@ is-color-stop@^1.0.0:
|
||||||
rgb-regex "^1.0.1"
|
rgb-regex "^1.0.1"
|
||||||
rgba-regex "^1.0.0"
|
rgba-regex "^1.0.0"
|
||||||
|
|
||||||
is-core-module@^2.2.0, is-core-module@^2.4.0:
|
is-core-module@^2.2.0, is-core-module@^2.6.0:
|
||||||
version "2.4.0"
|
version "2.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
|
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19"
|
||||||
integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==
|
integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
|
|
||||||
|
@ -6920,6 +6915,13 @@ json5@^2.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
minimist "^1.2.5"
|
minimist "^1.2.5"
|
||||||
|
|
||||||
|
json5@^2.2.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
|
||||||
|
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
|
||||||
|
dependencies:
|
||||||
|
minimist "^1.2.5"
|
||||||
|
|
||||||
jsonfile@^3.0.0:
|
jsonfile@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
|
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
|
||||||
|
@ -11015,13 +11017,12 @@ ts-essentials@^2.0.3:
|
||||||
resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745"
|
resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745"
|
||||||
integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==
|
integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==
|
||||||
|
|
||||||
tsconfig-paths@^3.9.0:
|
tsconfig-paths@^3.10.1:
|
||||||
version "3.9.0"
|
version "3.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
|
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz#79ae67a68c15289fdf5c51cb74f397522d795ed7"
|
||||||
integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==
|
integrity sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/json5" "^0.0.29"
|
json5 "^2.2.0"
|
||||||
json5 "^1.0.1"
|
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
|
@ -11783,10 +11784,10 @@ ws@^7.2.3, ws@^7.3.1:
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74"
|
||||||
integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==
|
integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==
|
||||||
|
|
||||||
ws@^8.1.0:
|
ws@^8.2.0:
|
||||||
version "8.1.0"
|
version "8.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.1.0.tgz#75e5ec608f66d3d3934ec6dbc4ebc8a34a68638c"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.0.tgz#0b738cd484bfc9303421914b11bb4011e07615bb"
|
||||||
integrity sha512-0UWlCD2s3RSclw8FN+D0zDTUyMO+1kHwJQQJzkgUh16S8d3NYON0AKCEQPffE0ez4JyRFu76QDA9KR5bOG/7jw==
|
integrity sha512-uYhVJ/m9oXwEI04iIVmgLmugh2qrZihkywG9y5FfZV2ATeLIzHf93qs+tUNqlttbQK957/VX3mtwAS+UfIwA4g==
|
||||||
|
|
||||||
xml-name-validator@^3.0.0:
|
xml-name-validator@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
|
|
Loading…
Reference in New Issue