Each email address change should be validated.
This commit is contained in:
parent
e2e77af4fa
commit
d24cb5d94e
8 changed files with 78 additions and 43 deletions
src
|
@ -39,5 +39,8 @@ require "./authd/exceptions"
|
||||||
# Requests and responses.
|
# Requests and responses.
|
||||||
require "./network"
|
require "./network"
|
||||||
|
|
||||||
|
# Run child processes.
|
||||||
|
require "./process"
|
||||||
|
|
||||||
# Functions to request the authd server.
|
# Functions to request the authd server.
|
||||||
require "./authd/client.cr"
|
require "./authd/client.cr"
|
||||||
|
|
|
@ -26,6 +26,10 @@ class AuthD::User
|
||||||
property activation_key : String? = nil
|
property activation_key : String? = nil
|
||||||
property email : String?
|
property email : String?
|
||||||
|
|
||||||
|
# Not yet validated email address: useful to keep a the previous validated email address
|
||||||
|
# until the new address is validated.
|
||||||
|
property pending_email : String? = nil
|
||||||
|
|
||||||
def initialize(@email = nil)
|
def initialize(@email = nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
24
src/process.cr
Normal file
24
src/process.cr
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
def run_process(cmd : String, params : Array(String), env : Hash(String, String))
|
||||||
|
unless Process.run(cmd, params, env,
|
||||||
|
true # clear environment
|
||||||
|
# input: Process::Redirect::Inherit,
|
||||||
|
# output: Process::Redirect::Inherit,
|
||||||
|
# error: Process::Redirect::Inherit
|
||||||
|
).success?
|
||||||
|
raise "cannot run #{cmd} #{params.join(" ")}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Send a token to recovery the user's password.
|
||||||
|
def send_recovery_token(authd : AuthD::Service, login : String, email : String, token : String)
|
||||||
|
run_process(authd.configuration.mailer_exe,
|
||||||
|
[ "send", authd.configuration.recovery_template, email ],
|
||||||
|
{ "HOME" => "/", "LOGIN" => login, "TOKEN" => token })
|
||||||
|
end
|
||||||
|
|
||||||
|
# Send a token to validate the user's email address.
|
||||||
|
def send_activation_token(authd : AuthD::Service, login : String, email : String, token : String)
|
||||||
|
run_process(authd.configuration.mailer_exe,
|
||||||
|
[ "send", authd.configuration.activation_template, email ],
|
||||||
|
{ "HOME" => "/", "LOGIN" => login, "TOKEN" => token })
|
||||||
|
end
|
|
@ -33,8 +33,28 @@ class AuthD::Request
|
||||||
cloned_user.password_hash = authd.hash_password s
|
cloned_user.password_hash = authd.hash_password s
|
||||||
end
|
end
|
||||||
|
|
||||||
@email.try do |email|
|
# In case of a new email address:
|
||||||
cloned_user.contact.email = email
|
# 1. the new address is stored as "pending_email"
|
||||||
|
# 2. the new address has to be validated before being used as primary email address
|
||||||
|
if email = @email
|
||||||
|
# Verify the email address isn't already in the database.
|
||||||
|
if authd.users_per_email.get? Base64.encode(email).chomp
|
||||||
|
return Response::ErrorEmailAddressAlreadyUsed.new
|
||||||
|
end
|
||||||
|
cloned_user.contact.pending_email = email
|
||||||
|
cloned_user.contact.new_activation_key
|
||||||
|
|
||||||
|
begin
|
||||||
|
u_login = cloned_user.login
|
||||||
|
u_email = cloned_user.contact.pending_email.not_nil!
|
||||||
|
u_activation_token = cloned_user.contact.activation_key.not_nil!
|
||||||
|
|
||||||
|
# Once the user is created and stored, we try to contact him.
|
||||||
|
send_activation_token authd, u_login, u_email, u_activation_token
|
||||||
|
rescue e
|
||||||
|
Baguette::Log.error "mailer: #{e}"
|
||||||
|
return Response::ErrorCannotContactUser.new
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -35,26 +35,11 @@ class AuthD::Request
|
||||||
user.password_renew_key.not_nil!
|
user.password_renew_key.not_nil!
|
||||||
end
|
end
|
||||||
|
|
||||||
mailer_exe = authd.configuration.mailer_exe
|
|
||||||
template_name = authd.configuration.recovery_template
|
|
||||||
|
|
||||||
u_login = user.login
|
u_login = user.login
|
||||||
u_email = user.contact.email.not_nil!
|
u_email = user.contact.email.not_nil!
|
||||||
u_token = user.password_renew_key.not_nil!
|
u_token = user.password_renew_key.not_nil!
|
||||||
|
|
||||||
# Once the user is created and stored, we try to contact him.
|
send_recovery_token authd, u_login, u_email, u_token
|
||||||
unless Process.run(mailer_exe,
|
|
||||||
# PARAMETERS
|
|
||||||
[ "send", template_name, u_email ],
|
|
||||||
# ENV
|
|
||||||
{ "HOME" => "/", "LOGIN" => u_login, "TOKEN" => u_token },
|
|
||||||
true # clear environment
|
|
||||||
# input: Process::Redirect::Inherit,
|
|
||||||
# output: Process::Redirect::Inherit,
|
|
||||||
# error: Process::Redirect::Inherit
|
|
||||||
).success?
|
|
||||||
raise "cannot contact user #{u_login} address #{u_email}"
|
|
||||||
end
|
|
||||||
|
|
||||||
Response::PasswordRecoverySent.new
|
Response::PasswordRecoverySent.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,13 +25,16 @@ class AuthD::Request
|
||||||
return Response::ErrorMailRequired.new
|
return Response::ErrorMailRequired.new
|
||||||
end
|
end
|
||||||
|
|
||||||
if ! @email.nil?
|
if m = @email
|
||||||
# Test on the email address format.
|
# Test on the email address format.
|
||||||
grok = Grok.new [ "%{EMAILADDRESS:email}" ]
|
grok = Grok.new [ "%{EMAILADDRESS:email}" ]
|
||||||
result = grok.parse @email.not_nil!
|
result = grok.parse m
|
||||||
email = result["email"]?
|
email = result["email"]?
|
||||||
|
|
||||||
return Response::ErrorInvalidEmailFormat.new if email.nil?
|
return Response::ErrorInvalidEmailFormat.new if email.nil?
|
||||||
|
|
||||||
|
# Verify the email address isn't already in the database.
|
||||||
|
return Response::ErrorEmailAddressAlreadyUsed.new if authd.users_per_email.get? Base64.encode(m).chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
# In this case we should not accept its registration.
|
# In this case we should not accept its registration.
|
||||||
|
@ -42,7 +45,7 @@ class AuthD::Request
|
||||||
password = authd.hash_password @password
|
password = authd.hash_password @password
|
||||||
|
|
||||||
user = User.new uid, @login, password
|
user = User.new uid, @login, password
|
||||||
user.contact.email = @email unless @email.nil?
|
user.contact.pending_email = @email unless @email.nil?
|
||||||
user.contact.new_activation_key
|
user.contact.new_activation_key
|
||||||
|
|
||||||
@profile.try do |profile|
|
@profile.try do |profile|
|
||||||
|
@ -52,26 +55,12 @@ class AuthD::Request
|
||||||
user.date_registration = Time.local
|
user.date_registration = Time.local
|
||||||
|
|
||||||
begin
|
begin
|
||||||
mailer_exe = authd.configuration.mailer_exe
|
u_login = user.login
|
||||||
template_name = authd.configuration.activation_template
|
u_email = user.contact.pending_email.not_nil!
|
||||||
|
u_activation_token = user.contact.activation_key.not_nil!
|
||||||
u_login = user.login
|
|
||||||
u_email = user.contact.email.not_nil!
|
|
||||||
u_activation_key = user.contact.activation_key.not_nil!
|
|
||||||
|
|
||||||
# Once the user is created and stored, we try to contact him.
|
# Once the user is created and stored, we try to contact him.
|
||||||
unless Process.run(mailer_exe,
|
send_activation_token authd, u_login, u_email, u_activation_token
|
||||||
# PARAMETERS
|
|
||||||
[ "send", template_name, u_email ],
|
|
||||||
# ENV
|
|
||||||
{ "HOME" => "/", "LOGIN" => u_login, "TOKEN" => u_activation_key },
|
|
||||||
true # clear environment
|
|
||||||
# input: Process::Redirect::Inherit,
|
|
||||||
# output: Process::Redirect::Inherit,
|
|
||||||
# error: Process::Redirect::Inherit
|
|
||||||
).success?
|
|
||||||
raise "cannot contact user #{u_login} address #{u_email}"
|
|
||||||
end
|
|
||||||
rescue e
|
rescue e
|
||||||
Baguette::Log.error "mailer: #{e}"
|
Baguette::Log.error "mailer: #{e}"
|
||||||
return Response::ErrorCannotContactUser.new
|
return Response::ErrorCannotContactUser.new
|
||||||
|
|
|
@ -17,13 +17,17 @@ class AuthD::Request
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove the user contact activation key: the email is validated.
|
# Remove the user contact activation key: the email is validated.
|
||||||
if user.contact.activation_key == @activation_key
|
if user.contact.activation_key != @activation_key
|
||||||
user.contact.activation_key = nil
|
|
||||||
else
|
|
||||||
return Response::ErrorInvalidActivationKey.new
|
return Response::ErrorInvalidActivationKey.new
|
||||||
end
|
end
|
||||||
|
|
||||||
authd.users_per_uid.update user.uid.to_s, user
|
cloned_user = user.clone
|
||||||
|
|
||||||
|
cloned_user.contact.activation_key = nil
|
||||||
|
cloned_user.contact.email = cloned_user.contact.pending_email
|
||||||
|
cloned_user.contact.pending_email = nil
|
||||||
|
|
||||||
|
authd.users_per_uid.update cloned_user
|
||||||
|
|
||||||
Response::UserValidated.new user.to_public
|
Response::UserValidated.new user.to_public
|
||||||
end
|
end
|
||||||
|
|
|
@ -108,4 +108,10 @@ class AuthD::Response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
AuthD.responses << ErrorEmailAddressNotValidated
|
AuthD.responses << ErrorEmailAddressNotValidated
|
||||||
|
|
||||||
|
IPC::JSON.message ErrorEmailAddressAlreadyUsed, 37 do
|
||||||
|
def initialize()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
AuthD.responses << ErrorEmailAddressAlreadyUsed
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue