From 682193d116cfb0ded09045e8cc75d219426398a6 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Wed, 30 Dec 2015 12:32:00 -0300 Subject: [PATCH] Updated Register Module. Worlflow 1- Register 1.1 Create a new temporal user 1.2 Email to the new User 1.3 Email to Web Master 2 Web Master Review th Account Application 2.1 Accept and Send an confirmation email to the user and remove the temporal user 2.2 Reject the application send a rejection email to the user and remove the temporal Added a new table to save temporal users to review their Application to the site. Updated Register Form with an new input Application and Recaptcha validation. Updated Emails templates and messages. (TODO improve messages) Updated mails templates. Simple messages (Todo improve messages). Added a new handler to reject a user Updated existing hanlders to handler the new workflow. --- .../demo/site/modules/auth/config/auth.json | 8 + .../mail_templates/account_activation.html | 12 +- .../account_activation_confirmation.html | 14 + .../mail_templates/account_evaluation.html | 26 ++ .../auth/mail_templates/account_rejected.html | 13 + .../modules/auth/scripts/auth_temp_user.sql | 13 + .../auth/templates/block_post_register.tpl | 2 +- .../modules/auth/templates/block_register.tpl | 15 +- library/email/email_service.e | 8 +- library/recaptcha/Readme.md | 4 + library/recaptcha/license.lic | 10 + library/recaptcha/recaptcha-safe.ecf | 20 ++ library/recaptcha/recaptcha.ecf | 22 ++ library/recaptcha/src/recaptcha_api.e | 147 ++++++++ library/recaptcha/test/application.e | 61 ++++ .../recaptcha/test/recaptcha_api_test_set.e | 69 ++++ library/recaptcha/test/test.ecf | 21 ++ modules/auth/auth-safe.ecf | 1 + modules/auth/cms_auth_api.e | 93 +++++ ..._authentication_email_service_parameters.e | 99 +++++- modules/auth/cms_authentication_module.e | 317 +++++++++++++++--- .../auth/cms_authenticaton_email_service.e | 52 ++- modules/auth/model/cms_temporal_user.e | 32 ++ modules/auth/persistence/cms_auth_storage_i.e | 75 +++++ .../auth/persistence/cms_auth_storage_null.e | 62 ++++ .../auth/persistence/cms_auth_storage_sql.e | 256 ++++++++++++++ modules/auth/site/config/auth.json | 8 + .../mail_templates/account_activation.html | 12 +- .../account_activation_confirmation.html | 14 + .../mail_templates/account_evaluation.html | 26 ++ .../site/mail_templates/account_rejected.html | 13 + modules/auth/site/scripts/auth_temp_user.tpl | 13 + .../site/templates/block_post_reactivate.tpl | 2 +- .../site/templates/block_post_register.tpl | 2 +- 34 files changed, 1457 insertions(+), 85 deletions(-) create mode 100644 examples/demo/site/modules/auth/config/auth.json create mode 100644 examples/demo/site/modules/auth/mail_templates/account_activation_confirmation.html create mode 100644 examples/demo/site/modules/auth/mail_templates/account_evaluation.html create mode 100644 examples/demo/site/modules/auth/mail_templates/account_rejected.html create mode 100644 examples/demo/site/modules/auth/scripts/auth_temp_user.sql create mode 100644 library/recaptcha/Readme.md create mode 100644 library/recaptcha/license.lic create mode 100644 library/recaptcha/recaptcha-safe.ecf create mode 100644 library/recaptcha/recaptcha.ecf create mode 100644 library/recaptcha/src/recaptcha_api.e create mode 100644 library/recaptcha/test/application.e create mode 100644 library/recaptcha/test/recaptcha_api_test_set.e create mode 100644 library/recaptcha/test/test.ecf create mode 100644 modules/auth/cms_auth_api.e create mode 100644 modules/auth/model/cms_temporal_user.e create mode 100644 modules/auth/persistence/cms_auth_storage_i.e create mode 100644 modules/auth/persistence/cms_auth_storage_null.e create mode 100644 modules/auth/persistence/cms_auth_storage_sql.e create mode 100644 modules/auth/site/config/auth.json create mode 100644 modules/auth/site/mail_templates/account_activation_confirmation.html create mode 100644 modules/auth/site/mail_templates/account_evaluation.html create mode 100644 modules/auth/site/mail_templates/account_rejected.html create mode 100644 modules/auth/site/scripts/auth_temp_user.tpl diff --git a/examples/demo/site/modules/auth/config/auth.json b/examples/demo/site/modules/auth/config/auth.json new file mode 100644 index 0000000..a81ab66 --- /dev/null +++ b/examples/demo/site/modules/auth/config/auth.json @@ -0,0 +1,8 @@ +{ + "email": "webmaster@eiffel.org", + "subject": "Thank you for contacting us", + "recaptcha": { + "site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD", + "secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx" + } +} diff --git a/examples/demo/site/modules/auth/mail_templates/account_activation.html b/examples/demo/site/modules/auth/mail_templates/account_activation.html index 0ab4c4f..0d404a0 100644 --- a/examples/demo/site/modules/auth/mail_templates/account_activation.html +++ b/examples/demo/site/modules/auth/mail_templates/account_activation.html @@ -1,5 +1,5 @@ - + Activation @@ -8,11 +8,7 @@ -

Thank you for registering at ROC CMS

- -

To complete your registration, please click on this link to activate your account:

- -

$link

-

Thank you for joining us.

+

Thank you for applying to ROC CMS $user

+

We will review your application and send you a resolution

- + \ No newline at end of file diff --git a/examples/demo/site/modules/auth/mail_templates/account_activation_confirmation.html b/examples/demo/site/modules/auth/mail_templates/account_activation_confirmation.html new file mode 100644 index 0000000..efc5087 --- /dev/null +++ b/examples/demo/site/modules/auth/mail_templates/account_activation_confirmation.html @@ -0,0 +1,14 @@ + + + + + Activation + + + + + +

Your account has been confirmed ROC CMS

+

Thank you for joining us.

+ + \ No newline at end of file diff --git a/examples/demo/site/modules/auth/mail_templates/account_evaluation.html b/examples/demo/site/modules/auth/mail_templates/account_evaluation.html new file mode 100644 index 0000000..002292d --- /dev/null +++ b/examples/demo/site/modules/auth/mail_templates/account_evaluation.html @@ -0,0 +1,26 @@ + + + + + Account Evaluation + + + + + +

Account Evaluation

+

The user $user ($email) wants to register to the site ROC CMS

+ +

This is his/her application.

+

$application

+
+ +

To complete the registration, please click on the following link to activate the user account:

+ +

$activate

+ +

To reject the registration, please click on the following link

+ +

$reject

+ + diff --git a/examples/demo/site/modules/auth/mail_templates/account_rejected.html b/examples/demo/site/modules/auth/mail_templates/account_rejected.html new file mode 100644 index 0000000..9cefb80 --- /dev/null +++ b/examples/demo/site/modules/auth/mail_templates/account_rejected.html @@ -0,0 +1,13 @@ + + + + + New Activation + + + + + +

You requested has been rejected, your application does not conform our rules ROC CMS

+ + \ No newline at end of file diff --git a/examples/demo/site/modules/auth/scripts/auth_temp_user.sql b/examples/demo/site/modules/auth/scripts/auth_temp_user.sql new file mode 100644 index 0000000..38ae29b --- /dev/null +++ b/examples/demo/site/modules/auth/scripts/auth_temp_user.sql @@ -0,0 +1,13 @@ + +DROP TABLE IF EXISTS "auth_temp_user"; +CREATE TABLE `auth_temp_user` ( + `uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` VARCHAR(100) NOT NULL, + `password` VARCHAR(100) NOT NULL, + `salt` VARCHAR(100) NOT NULL, + `email` VARCHAR(250) NOT NULL, + `application` TEXT NOT NULL, + CONSTRAINT `name` + UNIQUE(`name`) +); + diff --git a/examples/demo/site/modules/auth/templates/block_post_register.tpl b/examples/demo/site/modules/auth/templates/block_post_register.tpl index d59f75a..c76cbb5 100644 --- a/examples/demo/site/modules/auth/templates/block_post_register.tpl +++ b/examples/demo/site/modules/auth/templates/block_post_register.tpl @@ -1,3 +1,3 @@
-

Thanks for register, check your email to activate your account.

+

Thanks for your application, we will review it to activate your account.

diff --git a/examples/demo/site/modules/auth/templates/block_register.tpl b/examples/demo/site/modules/auth/templates/block_register.tpl index 9e7c478..2b56ea9 100644 --- a/examples/demo/site/modules/auth/templates/block_register.tpl +++ b/examples/demo/site/modules/auth/templates/block_register.tpl @@ -20,8 +20,19 @@ {$error_email/}
{/if} - - +
+ + + {if isset="$error_application"} + {$error_application/}
+ {/if} +
+ {unless isempty="$recaptcha_site_key"} +
+
+ {/unless} diff --git a/library/email/email_service.e b/library/email/email_service.e index 1e1c19b..03073a7 100644 --- a/library/email/email_service.e +++ b/library/email/email_service.e @@ -35,12 +35,14 @@ feature {NONE} -- Initialization parameters: EMAIL_SERVICE_PARAMETERS -- Associated parameters. - admin_email: IMMUTABLE_STRING_8 - -- Site admin's email. - mailer: NOTIFICATION_MAILER -- SMTP protocol. +feature -- Access + + admin_email: IMMUTABLE_STRING_8 + -- Site admin's email. + feature -- Basic Operations send_internal_email (a_content: READABLE_STRING_GENERAL) diff --git a/library/recaptcha/Readme.md b/library/recaptcha/Readme.md new file mode 100644 index 0000000..aaa8522 --- /dev/null +++ b/library/recaptcha/Readme.md @@ -0,0 +1,4 @@ +Recaptcha Eiffel Lbrary + +Based on https://developers.google.com/recaptcha/ + diff --git a/library/recaptcha/license.lic b/library/recaptcha/license.lic new file mode 100644 index 0000000..93c113a --- /dev/null +++ b/library/recaptcha/license.lic @@ -0,0 +1,10 @@ +${NOTE_KEYWORD} + copyright: "2011-${YEAR} Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" diff --git a/library/recaptcha/recaptcha-safe.ecf b/library/recaptcha/recaptcha-safe.ecf new file mode 100644 index 0000000..ca1015e --- /dev/null +++ b/library/recaptcha/recaptcha-safe.ecf @@ -0,0 +1,20 @@ + + + + + + /.git$ + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + + diff --git a/library/recaptcha/recaptcha.ecf b/library/recaptcha/recaptcha.ecf new file mode 100644 index 0000000..ad960b8 --- /dev/null +++ b/library/recaptcha/recaptcha.ecf @@ -0,0 +1,22 @@ + + + + + + /.git$ + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + + + + diff --git a/library/recaptcha/src/recaptcha_api.e b/library/recaptcha/src/recaptcha_api.e new file mode 100644 index 0000000..1149a4b --- /dev/null +++ b/library/recaptcha/src/recaptcha_api.e @@ -0,0 +1,147 @@ +note + description: "[ + Simple API to call {RECAPTCHA} Google API. + Example call: + https://www.google.com/recaptcha/api/siteverify?secret=your_secret&response=response_string&remoteip=user_ip_address + ]" + date: "$Date: 2015-01-28 11:44:15 -0300 (mi. 28 de ene. de 2015) $" + revision: "$Revision: 96551 $" + EIS: "name=RECAPTCHA", "src=https://developers.google.com/recaptcha/", "protocol=uri" + EIS: "name=RECAPTCHA API verify", "src=https://developers.google.com/recaptcha/docs/verify", "protocol=uri" + +class + RECAPTCHA_API + +create + make + +feature {NONE} -- Initialization + + make (a_secret_key, a_response: READABLE_STRING_8) + -- Create an object Recaptcha with secret key `a_secret_key' and response token `a_response'. + do + secret := a_secret_key + response := a_response + ensure + secret_set: secret.same_string (a_secret_key) + response_set: response.same_string (a_response) + end + +feature -- Access + + base_uri: STRING_8 = "https://www.google.com/recaptcha/api/siteverify" + -- Recaptcha base URI + + secret: READABLE_STRING_8 + -- Required. The shared key between your site and ReCAPTCHA. + + response: READABLE_STRING_8 + -- Required. The user response token provided by the reCAPTCHA to the user and provided to your site on. + + remoteip: detachable READABLE_STRING_8 + -- Optional. The user's IP address. + +feature -- Status Reports + + errors: detachable LIST [READABLE_STRING_8] + -- optional table of error codes + -- missing-input-secret The secret parameter is missing. + -- invalid-input-secret The secret parameter is invalid or malformed. + -- missing-input-response The response parameter is missing. + -- invalid-input-response The response parameter is invalid or malformed. + +feature -- Change Element + + set_remoteip (a_remoteip: READABLE_STRING_8) + -- Set `remoteip' with `a_remoteip'. + do + remoteip := a_remoteip + ensure + remoteip_set: remoteip = a_remoteip + end + +feature -- API + + verify: BOOLEAN + -- Verify the user's response + local + l_parser: JSON_PARSER + do + if attached get as l_response then + if attached l_response.body as l_body then + create l_parser.make_with_string (l_body) + l_parser.parse_content + if + l_parser.is_parsed and then attached {JSON_OBJECT} l_parser.parsed_json_object as jv and then + attached {JSON_BOOLEAN} jv.item ("success") as l_success + then + Result := l_success.item + if not Result and then attached {JSON_ARRAY} jv.item ("error-codes") as l_error_codes then + across + l_error_codes as c + loop + if attached {JSON_STRING} c.item as ji then + put_error (ji.unescaped_string_32) + end + end + end + end + else + put_error (l_response.status.out) + end + else + put_error ("unknown") + end + end + +feature {NONE} -- REST API + + get: detachable RESPONSE + -- Reading Data + local + l_request: REQUEST + do + create l_request.make ("GET", new_uri) + Result := l_request.execute + end + +feature {NONE} -- Implementation + + new_uri: STRING_8 + -- new uri (BaseUri?secret=secret_value&response=response_value[&remoteip=remoteip_value] + do + create Result.make_from_string (base_uri) + Result.append ("?secret=") + Result.append (secret) + Result.append ("&response=") + Result.append (response) + if attached remoteip as l_remoteip then + Result.append ("&remoteip=" + l_remoteip) + end + end + + put_error (a_code: READABLE_STRING_GENERAL) + local + l_errors: like errors + utf: UTF_CONVERTER + do + l_errors := errors + if l_errors = Void then + create {ARRAYED_LIST [STRING]} l_errors.make (1) + errors := l_errors + end + l_errors.force (utf.utf_32_string_to_utf_8_string_8 (a_code)) + end + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end diff --git a/library/recaptcha/test/application.e b/library/recaptcha/test/application.e new file mode 100644 index 0000000..2e0e25b --- /dev/null +++ b/library/recaptcha/test/application.e @@ -0,0 +1,61 @@ +note + description : "test application root class" + date : "$Date: 2015-01-14 15:37:57 -0300 (mi. 14 de ene. de 2015) $" + revision : "$Revision: 96458 $" + +class + APPLICATION + +inherit + ARGUMENTS + +create + make + +feature {NONE} -- Initialization + + make + -- Run application. + do + test_invalid_input + test_missing_input + test_missing_key_input + end + + + test_invalid_input + -- invalid-input-response + local + l_captcha: RECAPTCHA_API + do + create l_captcha.make ("","234") + check + not_true:not l_captcha.verify + end + end + + test_missing_input + -- missing-input-response + local + l_captcha: RECAPTCHA_API + do + create l_captcha.make ("key","") + check + not_true:not l_captcha.verify + end + end + + test_missing_key_input + -- missing-input-response + -- invalid-input-response + local + l_captcha: RECAPTCHA_API + do + create l_captcha.make ("","") + l_captcha.set_remoteip("localhost") + check + not_true:not l_captcha.verify + end + end + +end diff --git a/library/recaptcha/test/recaptcha_api_test_set.e b/library/recaptcha/test/recaptcha_api_test_set.e new file mode 100644 index 0000000..4deb220 --- /dev/null +++ b/library/recaptcha/test/recaptcha_api_test_set.e @@ -0,0 +1,69 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date: 2015-01-14 15:37:57 -0300 (mi. 14 de ene. de 2015) $" + revision: "$Revision: 96458 $" + testing: "type/manual" + +class + RECAPTCHA_API_TEST_SET + +inherit + EQA_TEST_SET + +feature -- Test routines + + test_invalid_input + -- invalid-input-response + local + l_captcha: RECAPTCHA_API + do + create l_captcha.make ("","234") + check + not_true:not l_captcha.verify + end + assert ("Not true", not l_captcha.verify) + assert ("Has error invalid-input-response",has_error (l_captcha,"invalid-input-response")) + end + + test_missing_input + -- missing-input-response + local + l_captcha: RECAPTCHA_API + do + create l_captcha.make ("key","") + check + not_true:not l_captcha.verify + end + assert ("Not true", not l_captcha.verify) + assert ("Has error missing-input-response",has_error (l_captcha,"missing-input-response")) + end + + test_missing_key_input + -- missing-input-response + -- invalid-input-response + local + l_captcha: RECAPTCHA_API + do + create l_captcha.make ("","") + l_captcha.set_remoteip("localhost") + assert ("Not true", not l_captcha.verify) + assert ("Has error missing-input-response",has_error (l_captcha,"missing-input-response")) + assert ("Has error invalid-input-response",has_error (l_captcha,"invalid-input-response")) + end + +feature {NONE} -- Implementation + + has_error (l_captcha: RECAPTCHA_API; a_error: READABLE_STRING_32): BOOLEAN + do + if attached l_captcha.errors as l_errors then + l_errors.compare_objects + Result := l_errors.has (a_error) + end + end + +end + + diff --git a/library/recaptcha/test/test.ecf b/library/recaptcha/test/test.ecf new file mode 100644 index 0000000..879c446 --- /dev/null +++ b/library/recaptcha/test/test.ecf @@ -0,0 +1,21 @@ + + + + + + + + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + diff --git a/modules/auth/auth-safe.ecf b/modules/auth/auth-safe.ecf index 5824089..29c2183 100644 --- a/modules/auth/auth-safe.ecf +++ b/modules/auth/auth-safe.ecf @@ -23,6 +23,7 @@ + diff --git a/modules/auth/cms_auth_api.e b/modules/auth/cms_auth_api.e new file mode 100644 index 0000000..22bbf0d --- /dev/null +++ b/modules/auth/cms_auth_api.e @@ -0,0 +1,93 @@ +note + description: "Summary description for {CMS_AUTH_API}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CMS_AUTH_API + +inherit + CMS_MODULE_API + + REFACTORING_HELPER + +create {CMS_AUTHENTICATION_MODULE} + make_with_storage + +feature {NONE} -- Initialization + + make_with_storage (a_api: CMS_API; a_auth_storage: CMS_AUTH_STORAGE_I) + -- Create an object with api `a_api' and storage `a_auth_storage'. + do + auth_storage := a_auth_storage + make (a_api) + ensure + auht_storage_set: auth_storage = a_auth_storage + end + +feature -- Access + + user_by_name (a_username: READABLE_STRING_32): detachable CMS_USER + -- User by name `a_user_name', if any. + do + Result := auth_storage.user_by_name (a_username) + end + + user_by_email (a_email: READABLE_STRING_32): detachable CMS_USER + -- User by email `a_email', if any. + do + Result := auth_storage.user_by_email (a_email) + end + + user_by_activation_token (a_token: READABLE_STRING_32): detachable CMS_USER + -- User by activation token `a_token'. + do + Result := auth_storage.user_by_activation_token (a_token) + end + + +feature -- Temp User + + new_temp_user (a_user: CMS_TEMPORAL_USER) + -- Add a new user `a_user'. + require + no_id: not a_user.has_id + no_hashed_password: a_user.hashed_password = Void + do + reset_error + if + attached a_user.password as l_password and then + attached a_user.email as l_email + then + auth_storage.new_temp_user (a_user) + error_handler.append (storage.error_handler) + else + error_handler.add_custom_error (0, "bad new user request", "Missing password or email to create new user!") + end + end + + remove_activation (a_token: READABLE_STRING_32) + -- Remove activation token `a_token', from the storage. + do + auth_storage.remove_activation (a_token) + end + + delete_user (a_user: CMS_TEMPORAL_USER) + -- Delete user `a_user'. + require + has_id: a_user.has_id + do + reset_error + auth_storage.delete_user (a_user) + error_handler.append (storage.error_handler) + end + +feature {CMS_MODULE} -- Access: User auth storage. + + auth_storage: CMS_AUTH_STORAGE_I + -- storage interface. + +feature -- Access: User Temp + +end diff --git a/modules/auth/cms_authentication_email_service_parameters.e b/modules/auth/cms_authentication_email_service_parameters.e index efb7b2a..d340cf5 100644 --- a/modules/auth/cms_authentication_email_service_parameters.e +++ b/modules/auth/cms_authentication_email_service_parameters.e @@ -88,6 +88,11 @@ feature {NONE} -- Initialization contact_subject_oauth := "Welcome." end + contact_subject_account_evaluation := "New register, account evalution" + + contact_subject_rejected := "Your account was rejected" + + contact_subject_activated := "Your account was activated" end feature -- Access @@ -101,10 +106,20 @@ feature -- Access contact_email: IMMUTABLE_STRING_8 -- Contact email. + contact_subject_account_evaluation: IMMUTABLE_STRING_8 contact_subject_register: IMMUTABLE_STRING_8 contact_subject_activate: IMMUTABLE_STRING_8 contact_subject_password: IMMUTABLE_STRING_8 contact_subject_oauth: IMMUTABLE_STRING_8 + contact_subject_rejected: IMMUTABLE_STRING_8 + contact_subject_activated: IMMUTABLE_STRING_8 + + + account_evaluation: STRING + -- Account evaluation template email message. + do + Result := template_string ("account_evaluation.html", default_template_account_evaluation) + end account_activation: STRING -- Account activation template email message. @@ -112,12 +127,24 @@ feature -- Access Result := template_string ("account_activation.html", default_template_account_activation) end + account_activation_confirmation: STRING + -- Account activation confirmation template email message. + do + Result := template_string ("account_activation_confirmation.html", default_template_account_activation_confirmation) + end + account_re_activation: STRING -- Account re_activation template email message. do Result := template_string ("accunt_re_activation.html", default_template_account_re_activation) end + account_rejected: STRING + -- Account rejected template email message. + do + Result := template_string ("accunt_rejected.html", default_template_account_rejected) + end + account_password: STRING -- Account password template email message. do @@ -146,7 +173,7 @@ feature {NONE} -- Implementation: Template local p: PATH do - p := template_path ("account_activation.html") + p := template_path (a_name) if attached read_template_file (p) as l_content then Result := l_content else @@ -177,6 +204,36 @@ feature {NONE} -- Implementation feature {NONE} -- Message email + default_template_account_evaluation: STRING = "[ + + + + + Account Evaluation + + + + + +

Account Evaluation

+

The user $user ($email) wants to register to the site

+ +

This is his/her application.

+

$application

+
+ +

To complete the registration, please click on the following link to activate the user account:

+ +

$activate

+ +

To reject the registration, please click on the following link

+ +

$reject

+ + + ]" + + default_template_account_activation: STRING = "[ @@ -188,17 +245,49 @@ feature {NONE} -- Message email -

Thank you for registering at ROC CMS

+

Thank you for applying to ROC CMS $user

-

To complete your registration, please click on the following link to activate your account:

- -

$link

+

We will review your application and send you an email

Thank you for joining us.

]" + default_template_account_activation_confirmation: STRING = "[ + + + + + Activation + + + + + +

Your account has been confirmed ROC CMS $email

+ +

Thank you for joining us.

+ + + ]" + + default_template_account_rejected: STRING = "[ + + + + + New Activation + + + + + +

You requested has been rejected, your application does not conform our rules ROC CMS

+ + + ]" + default_template_account_re_activation: STRING = "[ diff --git a/modules/auth/cms_authentication_module.e b/modules/auth/cms_authentication_module.e index 3787b75..b4bba83 100644 --- a/modules/auth/cms_authentication_module.e +++ b/modules/auth/cms_authentication_module.e @@ -8,13 +8,20 @@ class inherit CMS_MODULE + rename + module_api as auth_api redefine setup_hooks, - permissions + permissions, + initialize, + install, + auth_api end CMS_HOOK_AUTO_REGISTER + CMS_HOOK_RESPONSE_ALTER + CMS_HOOK_VALUE_TABLE_ALTER CMS_HOOK_BLOCK @@ -74,6 +81,53 @@ feature -- Access: docs Result := cache_duration = 0 end +feature {CMS_API} -- Module Initialization + + initialize (a_api: CMS_API) + -- + local + l_auth_api: like auth_api + l_user_auth_storage: CMS_AUTH_STORAGE_I + do + Precursor (a_api) + + -- Storage initialization + if attached a_api.storage.as_sql_storage as l_storage_sql then + create {CMS_AUTH_STORAGE_SQL} l_user_auth_storage.make (l_storage_sql) + else + -- FIXME: in case of NULL storage, should Current be disabled? + create {CMS_AUTH_STORAGE_NULL} l_user_auth_storage + end + + -- API initialization + create l_auth_api.make_with_storage (a_api, l_user_auth_storage) + auth_api := l_auth_api + ensure then + auth_api_set: auth_api /= Void + end + + install (api: CMS_API) + do + -- Schema + if attached api.storage.as_sql_storage as l_sql_storage then + if not l_sql_storage.sql_table_exists ("auth_temp_user") then + --| Schema + l_sql_storage.sql_execute_file_script (api.module_resource_location (Current, (create {PATH}.make_from_string ("scripts")).extended ("auth_temp_user.sql")), Void) + + if l_sql_storage.has_error then + api.logger.put_error ("Could not initialize database for auth_module", generating_type) + end + end + l_sql_storage.sql_finalize + Precursor {CMS_MODULE}(api) + end + end + +feature {CMS_API} -- Access: API + + auth_api: detachable CMS_AUTH_API + -- + feature -- Router setup_router (a_router: WSF_ROUTER; a_api: CMS_API) @@ -89,6 +143,7 @@ feature -- Router a_router.handle ("/account/roc-logout", create {WSF_URI_AGENT_HANDLER}.make (agent handle_logout (a_api, ?, ?)), a_router.methods_head_get) a_router.handle ("/account/roc-register", create {WSF_URI_AGENT_HANDLER}.make (agent handle_register (a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/activate/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_activation (a_api, ?, ?)), a_router.methods_head_get) + a_router.handle ("/account/reject/{token}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_reject (a_api, ?, ?)), a_router.methods_head_get) a_router.handle ("/account/reactivate", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reactivation (a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/new-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_new_password (a_api, ?, ?)), a_router.methods_get_post) a_router.handle ("/account/reset-password", create {WSF_URI_AGENT_HANDLER}.make (agent handle_reset_password (a_api, ?, ?)), a_router.methods_get_post) @@ -182,53 +237,82 @@ feature -- Handler local r: CMS_RESPONSE l_user_api: CMS_USER_API - u: CMS_USER + u: CMS_TEMPORAL_USER l_exist: BOOLEAN es: CMS_AUTHENTICATON_EMAIL_SERVICE - l_url: STRING + l_url_activate: STRING + l_url_reject: STRING l_token: STRING + l_captcha_passed: BOOLEAN do create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) - if r.has_permission ("account register") then + if + r.has_permission ("account register") and then + attached auth_api as l_auth_api + then if req.is_post_request_method then if attached {WSF_STRING} req.form_parameter ("name") as l_name and then attached {WSF_STRING} req.form_parameter ("password") as l_password and then - attached {WSF_STRING} req.form_parameter ("email") as l_email + attached {WSF_STRING} req.form_parameter ("email") as l_email and then + attached {WSF_STRING} req.form_parameter ("application") as l_application then l_user_api := api.user_api - if attached l_user_api.user_by_name (l_name.value) then + if attached l_user_api.user_by_name (l_name.value) or else attached l_auth_api.user_by_name (l_name.value) then -- Username already exist. r.set_value ("User name already exists!", "error_name") l_exist := True end - if attached l_user_api.user_by_email (l_email.value) then + if attached l_user_api.user_by_email (l_email.value) or else attached l_auth_api.user_by_email (l_email.value) then -- Emails already exist. r.set_value ("An account is already associated with that email address!", "error_email") l_exist := True end + if attached recaptcha_secret_key (api) as l_recaptcha_key then + if + attached {WSF_STRING} req.form_parameter ("g-recaptcha-response") as l_recaptcha_response and then + is_captcha_verified (l_recaptcha_key, l_recaptcha_response.value) + then + l_captcha_passed := True + else + --| Bad or missing captcha + l_captcha_passed := False + end + else + --| reCaptcha is not setup, so no verification + l_captcha_passed := True + end + if not l_exist then - -- New user + + -- New temp user create u.make (l_name.value) u.set_email (l_email.value) u.set_password (l_password.value) - l_user_api.new_user (u) + u.set_application (l_application.value) + l_auth_api.new_temp_user (u) -- Create activation token l_token := new_token l_user_api.new_activation (l_token, u.id) - l_url := req.absolute_script_url ("/account/activate/" + l_token) + l_url_activate := req.absolute_script_url ("/account/activate/" + l_token) + l_url_reject := req.absolute_script_url ("/account/reject/" + l_token) - -- Send Email + -- Send Email to webmaster + create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) + write_debug_log (generator + ".handle register: send_register_email") + es.send_account_evaluation (u, l_application.value, l_url_activate, l_url_reject) + + -- Send Email to user create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) write_debug_log (generator + ".handle register: send_contact_email") - es.send_contact_email (l_email.value, l_url) - + es.send_contact_email (l_email.value, l_name.value) else r.set_value (l_name.value, "name") r.set_value (l_email.value, "email") + r.set_value (l_application.value, "application") r.set_status_code ({HTTP_CONSTANTS}.bad_request) end end @@ -246,67 +330,127 @@ feature -- Handler r: CMS_RESPONSE l_user_api: CMS_USER_API l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE + es: CMS_AUTHENTICATON_EMAIL_SERVICE do - l_user_api := api.user_api - create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) - if attached {WSF_STRING} req.path_parameter ("token") as l_token then + if attached auth_api as l_auth_api then + l_user_api := api.user_api + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + if attached {WSF_STRING} req.path_parameter ("token") as l_token then - if attached {CMS_USER} l_user_api.user_by_activation_token (l_token.value) as l_user then - -- Valid user_id - l_user.mark_active - l_user_api.update_user (l_user) - l_user_api.remove_activation (l_token.value) - r.set_main_content ("

Your account "+ l_user.name +" has been activated

") + if attached {CMS_TEMPORAL_USER} l_auth_api.user_by_activation_token (l_token.value) as l_user then + -- Delete temporal User + l_auth_api.delete_user (l_user) + + -- Valid user_id + l_user.set_id (0) + l_user.mark_active + l_user_api.new_user (l_user) + l_auth_api.remove_activation (l_token.value) + + r.set_main_content ("

The account "+ l_user.name +" has been activated

") + -- Send Email + if attached l_user.email as l_email then + create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) + write_debug_log (generator + ".handle register: send_contact_activation_confirmation_email") + es.send_contact_activation_confirmation_email (l_email, req.absolute_script_url ("")) + end + else + -- the token does not exist, or it was already used. + r.set_status_code ({HTTP_CONSTANTS}.bad_request) + r.set_main_content ("

The token " + l_token.value +" is not valid " + r.link ("Reactivate Account", "account/reactivate", Void) + "

") + end + r.execute else - -- the token does not exist, or it was already used. - r.set_status_code ({HTTP_CONSTANTS}.bad_request) - r.set_main_content ("

The token " + l_token.value +" is not valid " + r.link ("Reactivate Account", "account/reactivate", Void) + "

") + create l_ir.make (req, res, api) + l_ir.execute end - r.execute else - create l_ir.make (req, res, api) - l_ir.execute + create {INTERNAL_SERVER_ERROR_CMS_RESPONSE} r.make (req, res, api) +-- r.set_main_content ("...") + r.execute end end + handle_reject (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) + local + r: CMS_RESPONSE + l_user_api: CMS_USER_API + l_ir: INTERNAL_SERVER_ERROR_CMS_RESPONSE + es: CMS_AUTHENTICATON_EMAIL_SERVICE + do + if attached auth_api as l_auth_api then + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + if attached {WSF_STRING} req.path_parameter ("token") as l_token then + if attached {CMS_TEMPORAL_USER} l_auth_api.user_by_activation_token (l_token.value) as l_user then + l_auth_api.delete_user (l_user) + r.set_main_content ("

The temporal account for "+ l_user.name +" has been removed

") + -- Send Email + if attached l_user.email as l_email then + create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) + write_debug_log (generator + ".handle register: send_contact_activation_reject_email") + es.send_contact_activation_reject_email (l_email, req.absolute_script_url ("")) + end + else + -- the token does not exist, or it was already used. + r.set_status_code ({HTTP_CONSTANTS}.bad_request) + r.set_main_content ("

The token " + l_token.value +" is not valid ") + end + r.execute + else + create l_ir.make (req, res, api) + l_ir.execute + end + else + create {INTERNAL_SERVER_ERROR_CMS_RESPONSE} r.make (req, res, api) + r.execute + end + end + handle_reactivation (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) local r: CMS_RESPONSE es: CMS_AUTHENTICATON_EMAIL_SERVICE l_user_api: CMS_USER_API l_token: STRING - l_url: STRING + l_url_activate: STRING + l_url_reject: STRING do - create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) - if req.is_post_request_method then - if - attached {WSF_STRING} req.form_parameter ("email") as l_email - then - l_user_api := api.user_api - if attached {CMS_USER} l_user_api.user_by_email (l_email.value) as l_user then - -- User exist create a new token and send a new email. - if l_user.is_active then - r.set_value ("The asociated user to the given email " + l_email.value + " , is already active", "is_active") - r.set_status_code ({HTTP_CONSTANTS}.bad_request) - else - l_token := new_token - l_user_api.new_activation (l_token, l_user.id) - l_url := req.absolute_script_url ("/account/activate/" + l_token) + if attached auth_api as l_auth_api then + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + if req.is_post_request_method then + if + attached {WSF_STRING} req.form_parameter ("email") as l_email + then + l_user_api := api.user_api + if attached {CMS_TEMPORAL_USER} l_auth_api.user_by_email (l_email.value) as l_user then + -- User exist create a new token and send a new email. + if l_user.is_active then + r.set_value ("The asociated user to the given email " + l_email.value + " , is already active", "is_active") + r.set_status_code ({HTTP_CONSTANTS}.bad_request) + else + l_token := new_token + l_user_api.new_activation (l_token, l_user.id) + l_url_activate := req.absolute_script_url ("/account/activate/" + l_token) + l_url_reject := req.absolute_script_url ("/account/reject/" + l_token) - -- Send Email - create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) - write_debug_log (generator + ".handle register: send_contact_activation_email") - es.send_contact_activation_email (l_email.value, l_url) + -- Send Email to webmaster + if attached l_user.application as l_application then + create es.make (create {CMS_AUTHENTICATION_EMAIL_SERVICE_PARAMETERS}.make (api)) + write_debug_log (generator + ".handle register: send_register_email") + es.send_account_evaluation (l_user, l_application, l_url_activate, l_url_reject) + end + end + else + r.set_value ("The email does not exist or !", "error_email") + r.set_value (l_email.value, "email") + r.set_status_code ({HTTP_CONSTANTS}.bad_request) end - else - r.set_value ("The email does not exist or !", "error_email") - r.set_value (l_email.value, "email") - r.set_status_code ({HTTP_CONSTANTS}.bad_request) end end + else + create {INTERNAL_SERVER_ERROR_CMS_RESPONSE} r.make (req, res, api) end - r.execute end @@ -556,6 +700,9 @@ feature {NONE} -- Block views if a_response.has_permission ("account register") then if a_response.request.is_get_request_method then if attached template_block (a_block_id, a_response) as l_tpl_block then + if attached recaptcha_site_key (a_response.api) as l_recaptcha_site_key then + l_tpl_block.set_value (l_recaptcha_site_key, "recaptcha_site_key") + end a_response.add_block (l_tpl_block, "content") else debug ("cms") @@ -569,6 +716,9 @@ feature {NONE} -- Block views -- l_tpl_block.set_value (a_response.values.item ("error_email"), "error_email") -- l_tpl_block.set_value (a_response.values.item ("email"), "email") -- l_tpl_block.set_value (a_response.values.item ("name"), "name") + if attached recaptcha_site_key (a_response.api) as l_recaptcha_site_key then + l_tpl_block.set_value (l_recaptcha_site_key, "recaptcha_site_key") + end a_response.add_block (l_tpl_block, "content") else debug ("cms") @@ -693,6 +843,67 @@ feature {NONE} -- Block views end end + +feature -- Recaptcha + + recaptcha_secret_key (api: CMS_API): detachable READABLE_STRING_8 + -- Get recaptcha security key. + local + utf: UTF_CONVERTER + do + if attached api.module_configuration (Current, Void) as cfg then + if + attached cfg.text_item ("recaptcha.secret_key") as l_recaptcha_key and then + not l_recaptcha_key.is_empty + then + Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key) + end + end + end + + recaptcha_site_key (api: CMS_API): detachable READABLE_STRING_8 + -- Get recaptcha security key. + local + utf: UTF_CONVERTER + do + if attached api.module_configuration (Current, Void) as cfg then + if + attached cfg.text_item ("recaptcha.site_key") as l_recaptcha_key and then + not l_recaptcha_key.is_empty + then + Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key) + end + end + end + + +feature -- Response Alter + + response_alter (a_response: CMS_RESPONSE) + do + a_response.add_javascript_url ("https://www.google.com/recaptcha/api.js") + end + +feature {NONE} -- Implementation + + is_captcha_verified (a_secret, a_response: READABLE_STRING_8): BOOLEAN + local + api: RECAPTCHA_API + l_errors: STRING + do + write_debug_log (generator + ".is_captcha_verified with response: [" + a_response + "]") + create api.make (a_secret, a_response) + Result := api.verify + if not Result and then attached api.errors as l_api_errors then + create l_errors.make_empty + l_errors.append_character ('%N') + across l_api_errors as ic loop + l_errors.append ( ic.item ) + l_errors.append_character ('%N') + end + write_error_log (generator + ".is_captcha_verified api_errors [" + l_errors + "]") + end + end note copyright: "Copyright (c) 1984-2013, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" diff --git a/modules/auth/cms_authenticaton_email_service.e b/modules/auth/cms_authenticaton_email_service.e index d4a1984..48758f7 100644 --- a/modules/auth/cms_authenticaton_email_service.e +++ b/modules/auth/cms_authenticaton_email_service.e @@ -34,15 +34,34 @@ feature -- Access feature -- Basic Operations - send_contact_email (a_to, a_content: READABLE_STRING_8) - -- Send successful contact message `a_token' to `a_to'. + send_account_evaluation (a_user: CMS_USER; a_application, a_url_activate, a_url_reject: READABLE_STRING_8) + -- Send new user register to webmaster to confirm or reject itt. + local + l_message: STRING + do + create l_message.make_from_string (parameters.account_evaluation) + l_message.replace_substring_all ("$user", a_user.name) + if attached a_user.email as l_email then + l_message.replace_substring_all ("$email", l_email) + else + l_message.replace_substring_all ("$email", "unknown email") + end + l_message.replace_substring_all ("$application", a_application) + l_message.replace_substring_all ("$activate", a_url_activate) + l_message.replace_substring_all ("$reject", a_url_reject) + send_message (contact_email, contact_email, parameters.contact_subject_account_evaluation, l_message) + end + + + send_contact_email (a_to, a_user: READABLE_STRING_8) + -- Send successful contact message to `a_to'. require attached_to: a_to /= Void local l_message: STRING do create l_message.make_from_string (parameters.account_activation) - l_message.replace_substring_all ("$link", a_content) + l_message.replace_substring_all ("$user", a_user) send_message (contact_email, a_to, parameters.contact_subject_register, l_message) end @@ -60,6 +79,33 @@ feature -- Basic Operations end + send_contact_activation_confirmation_email (a_to, a_content: READABLE_STRING_8) + -- Send successful contact activation to a_to. + require + attached_to: a_to /= Void + local + l_message: STRING + do + create l_message.make_from_string (parameters.account_activation_confirmation) + l_message.replace_substring_all ("$email", a_content) + send_message (contact_email, a_to, parameters.contact_subject_activated, l_message) + end + + + send_contact_activation_reject_email (a_to, a_content: READABLE_STRING_8) + -- Send successful contact activation reject to `a_to'. + require + attached_to: a_to /= Void + local + l_message: STRING + do + create l_message.make_from_string (parameters.account_rejected) + l_message.replace_substring_all ("$link", a_content) + send_message (contact_email, a_to, parameters.contact_subject_activate, l_message) + end + + + send_contact_password_email (a_to, a_content: READABLE_STRING_8) -- Send successful contact message `a_token' to `a_to'. require diff --git a/modules/auth/model/cms_temporal_user.e b/modules/auth/model/cms_temporal_user.e new file mode 100644 index 0000000..4ea4af4 --- /dev/null +++ b/modules/auth/model/cms_temporal_user.e @@ -0,0 +1,32 @@ +note + description: "Summary description for {CMS_TEMPORAL_USER}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_TEMPORAL_USER + +inherit + + CMS_USER + +create + make, + make_with_id + +feature -- Access + + application: detachable STRING_32 + -- User application + +feature -- Element change + + set_application (an_application: like application) + -- Assign `application' with `an_application'. + do + application := an_application + ensure + application_assigned: application = an_application + end + +end diff --git a/modules/auth/persistence/cms_auth_storage_i.e b/modules/auth/persistence/cms_auth_storage_i.e new file mode 100644 index 0000000..48851ad --- /dev/null +++ b/modules/auth/persistence/cms_auth_storage_i.e @@ -0,0 +1,75 @@ +note + description: "[ + API to handle OAUTH storage + ]" + date: "$Date$" + revision: "$Revision$" + +deferred class + CMS_AUTH_STORAGE_I + +inherit + SHARED_LOGGER + +feature -- Error Handling + + error_handler: ERROR_HANDLER + -- Error handler. + deferred + end + +feature -- Access: Users + + user_temp_by_id (a_uid: like {CMS_USER}.id; a_consumer_table: READABLE_STRING_GENERAL): detachable CMS_USER + -- Retrieve a user by id `a_uid' for the consumer `a_consumer', if aby. + deferred + end + + user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER + -- User with name `a_name', if any. + require + a_name /= Void and then not a_name.is_empty + deferred + ensure + same_name: Result /= Void implies a_name ~ Result.name + password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void) + end + + user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER + -- User with name `a_email', if any. + deferred + ensure + same_email: Result /= Void implies a_email ~ Result.email + password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void) + end + + + user_by_activation_token (a_token: READABLE_STRING_32): detachable CMS_USER + -- User with activation token `a_token', if any. + deferred + ensure + password: Result /= Void implies (Result.hashed_password /= Void and Result.password = Void) + end + +feature -- New Temp User + + remove_activation (a_token: READABLE_STRING_32) + -- Remove activation by token `a_token'. + deferred + end + + new_temp_user (a_user: CMS_TEMPORAL_USER) + -- New temp user `a_user'. + require + no_id: not a_user.has_id + deferred + end + + delete_user (a_user: CMS_TEMPORAL_USER) + -- Delete user `a_user'. + require + has_id: a_user.has_id + deferred + end + +end diff --git a/modules/auth/persistence/cms_auth_storage_null.e b/modules/auth/persistence/cms_auth_storage_null.e new file mode 100644 index 0000000..505b558 --- /dev/null +++ b/modules/auth/persistence/cms_auth_storage_null.e @@ -0,0 +1,62 @@ +note + description: "Summary description for {CMS_AUTH_STORAGE_NULL}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_AUTH_STORAGE_NULL + +inherit + + CMS_AUTH_STORAGE_I + + +feature -- Error handler + + error_handler: ERROR_HANDLER + -- Error handler. + do + create Result.make + end + +feature -- Access: Users + + user_temp_by_id (a_uid: like {CMS_USER}.id; a_consumer_table: READABLE_STRING_GENERAL): detachable CMS_USER + -- + do + end + + user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER + -- + do + end + + user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER + -- + do + end + + user_by_activation_token (a_token: READABLE_STRING_32): detachable CMS_USER + -- + do + end + +feature -- Temp Users + + remove_activation (a_token: READABLE_STRING_32) + -- . + do + end + + new_temp_user (a_user: CMS_TEMPORAL_USER) + -- + do + end + + delete_user (a_user: CMS_TEMPORAL_USER) + -- + do + end + + +end diff --git a/modules/auth/persistence/cms_auth_storage_sql.e b/modules/auth/persistence/cms_auth_storage_sql.e new file mode 100644 index 0000000..ea2fe44 --- /dev/null +++ b/modules/auth/persistence/cms_auth_storage_sql.e @@ -0,0 +1,256 @@ +note + description: "Summary description for {CMS_AUTH_STORAGE_SQL}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_AUTH_STORAGE_SQL + +inherit + CMS_AUTH_STORAGE_I + + CMS_PROXY_STORAGE_SQL + + CMS_STORAGE_SQL_I + + REFACTORING_HELPER + +create + make + +feature -- Access User Outh + + + user_temp_by_id (a_uid: like {CMS_USER}.id; a_consumer: READABLE_STRING_GENERAL): detachable CMS_USER + -- + local + l_parameters: STRING_TABLE [detachable ANY] + l_string: STRING + do + error_handler.reset + write_information_log (generator + ".user_temp_by_id") + create l_parameters.make (1) + l_parameters.put (a_uid, "uid") + create l_string.make_from_string (select_user_auth_temp_by_id) + sql_query (l_string, l_parameters) + if not has_error and not sql_after then + Result := fetch_user + sql_forth + if not sql_after then + check no_more_than_one: False end + Result := Void + end + end + sql_finalize + end + + user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER + -- User for the given name `a_name', if any. + local + l_parameters: STRING_TABLE [detachable ANY] + do + error_handler.reset + write_information_log (generator + ".user_by_name") + create l_parameters.make (1) + l_parameters.put (a_name, "name") + sql_query (select_user_by_name, l_parameters) + if not sql_after then + Result := fetch_user + sql_forth + check one_row: sql_after end + end + sql_finalize + end + + user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER + -- User for the given email `a_email', if any. + local + l_parameters: STRING_TABLE [detachable ANY] + do + error_handler.reset + write_information_log (generator + ".user_by_email") + create l_parameters.make (1) + l_parameters.put (a_email, "email") + sql_query (select_user_by_email, l_parameters) + if not sql_after then + Result := fetch_user + sql_forth + check one_row: sql_after end + end + sql_finalize + end + + user_by_activation_token (a_token: READABLE_STRING_32): detachable CMS_USER + -- User for the given activation token `a_token', if any. + local + l_parameters: STRING_TABLE [detachable ANY] + do + error_handler.reset + write_information_log (generator + ".user_by_activation_token") + create l_parameters.make (1) + l_parameters.put (a_token, "token") + sql_query (select_user_by_activation_token, l_parameters) + if not sql_after then + Result := fetch_user + sql_forth + check one_row: sql_after end + end + sql_finalize + end + + +feature {NONE} -- Implementation: User + + fetch_user: detachable CMS_TEMPORAL_USER + local + l_id: INTEGER_64 + l_name: detachable READABLE_STRING_32 + do + if attached sql_read_integer_64 (1) as i then + l_id := i + end + if attached sql_read_string_32 (2) as s and then not s.is_whitespace then + l_name := s + end + + if l_name /= Void then + create Result.make (l_name) + if l_id > 0 then + Result.set_id (l_id) + end + elseif l_id > 0 then + create Result.make_with_id (l_id) + end + + if Result /= Void then + if attached sql_read_string (3) as l_password then + -- FIXME: should we return the password here ??? + Result.set_password (l_password) + end + if attached sql_read_string (5) as l_email then + Result.set_email (l_email) + end + if attached sql_read_string (6) as l_application then + Result.set_application (l_application) + end + else + check expected_valid_user: False end + end + end + + +feature -- New Temp User + + new_temp_user (a_user: CMS_TEMPORAL_USER) + -- Add a new temp_user `a_user'. + local + l_parameters: STRING_TABLE [detachable ANY] + l_password_salt, l_password_hash: STRING + l_security: SECURITY_PROVIDER + do + error_handler.reset + if + attached a_user.password as l_password and then + attached a_user.email as l_email and then + attached a_user.application as l_application + then + + create l_security + l_password_salt := l_security.salt + l_password_hash := l_security.password_hash (l_password, l_password_salt) + + write_information_log (generator + ".new_temp_user") + create l_parameters.make (4) + l_parameters.put (a_user.name, "name") + l_parameters.put (l_password_hash, "password") + l_parameters.put (l_password_salt, "salt") + l_parameters.put (l_email, "email") + l_parameters.put (l_application, "application") + + sql_begin_transaction + sql_insert (sql_insert_user, l_parameters) + if not error_handler.has_error then + a_user.set_id (last_inserted_user_id) + sql_commit_transaction + else + sql_rollback_transaction + end + sql_finalize + else + -- set error + error_handler.add_custom_error (-1, "bad request" , "Missing password or email") + end + end + + +feature -- Remove Activation + + remove_activation (a_token: READABLE_STRING_32) + -- . + local + l_parameters: STRING_TABLE [detachable ANY] + do + error_handler.reset + sql_begin_transaction + write_information_log (generator + ".remove_activation") + create l_parameters.make (1) + l_parameters.put (a_token, "token") + sql_modify (sql_remove_activation, l_parameters) + sql_commit_transaction + sql_finalize + end + + delete_user (a_user: CMS_TEMPORAL_USER) + -- Delete user `a_user'. + local + l_parameters: STRING_TABLE [detachable ANY] + do + error_handler.reset + sql_begin_transaction + write_information_log (generator + ".delete_user") + create l_parameters.make (1) + l_parameters.put (a_user.id, "uid") + sql_modify (sql_delete_user, l_parameters) + sql_commit_transaction + sql_finalize + end +feature {NONE} -- Implementation + + last_inserted_user_id: INTEGER_64 + -- Last insert user id. + do + error_handler.reset + write_information_log (generator + ".last_inserted_user_id") + sql_query (Sql_last_insert_user_id, Void) + if not sql_after then + Result := sql_read_integer_64 (1) + sql_forth + check one_row: sql_after end + end + sql_finalize + end + +feature {NONE} -- SQL select + + Sql_last_insert_user_id: STRING = "SELECT MAX(uid) FROM auth_temp_user;" + + Select_user_auth_temp_by_id: STRING = "SELECT uid, name, password, salt, email, application FROM auth_temp_user as u where uid=:uid;" + + + sql_insert_user: STRING = "INSERT INTO auth_temp_user (name, password, salt, email, application) VALUES (:name, :password, :salt, :email, :application);" + -- SQL Insert to add a new user. + + Select_user_by_name: STRING = "SELECT uid, name, password, salt, email, application FROM auth_temp_user WHERE name =:name;" + -- Retrieve user by name if exists. + + Select_user_by_email: STRING = "SELECT uid, name, password, salt, email, application FROM auth_temp_user WHERE email =:email;" + -- Retrieve user by email if exists. + + Select_user_by_activation_token: STRING = "SELECT u.uid, u.name, u.password, u.salt, u.email, u.application FROM auth_temp_user as u JOIN users_activations as ua ON ua.uid = u.uid and ua.token = :token;" + -- Retrieve user by activation token if exist. + + Sql_remove_activation: STRING = "DELETE FROM users_activations WHERE token = :token;" + -- Remove activation token. + + Sql_delete_user: STRING = "DELETE FROM auth_temp_user WHERE uid=:uid;" +end diff --git a/modules/auth/site/config/auth.json b/modules/auth/site/config/auth.json new file mode 100644 index 0000000..a81ab66 --- /dev/null +++ b/modules/auth/site/config/auth.json @@ -0,0 +1,8 @@ +{ + "email": "webmaster@eiffel.org", + "subject": "Thank you for contacting us", + "recaptcha": { + "site_key":"6Lex9RMTAAAAAKleC4x6TaRlFcpLbEWgH_U7MSiD", + "secret_key":"6Lex9RMTAAAAAAkBczvX5DUiyg_xoM_EthVVgRRx" + } +} diff --git a/modules/auth/site/mail_templates/account_activation.html b/modules/auth/site/mail_templates/account_activation.html index 0ab4c4f..0d404a0 100644 --- a/modules/auth/site/mail_templates/account_activation.html +++ b/modules/auth/site/mail_templates/account_activation.html @@ -1,5 +1,5 @@ - + Activation @@ -8,11 +8,7 @@ -

Thank you for registering at ROC CMS

- -

To complete your registration, please click on this link to activate your account:

- -

$link

-

Thank you for joining us.

+

Thank you for applying to ROC CMS $user

+

We will review your application and send you a resolution

- + \ No newline at end of file diff --git a/modules/auth/site/mail_templates/account_activation_confirmation.html b/modules/auth/site/mail_templates/account_activation_confirmation.html new file mode 100644 index 0000000..950fccf --- /dev/null +++ b/modules/auth/site/mail_templates/account_activation_confirmation.html @@ -0,0 +1,14 @@ + + + + + Activation + + + + + +

Your account has been confirmed ROC CMS $email

+

Thank you for joining us.

+ + \ No newline at end of file diff --git a/modules/auth/site/mail_templates/account_evaluation.html b/modules/auth/site/mail_templates/account_evaluation.html new file mode 100644 index 0000000..002292d --- /dev/null +++ b/modules/auth/site/mail_templates/account_evaluation.html @@ -0,0 +1,26 @@ + + + + + Account Evaluation + + + + + +

Account Evaluation

+

The user $user ($email) wants to register to the site ROC CMS

+ +

This is his/her application.

+

$application

+
+ +

To complete the registration, please click on the following link to activate the user account:

+ +

$activate

+ +

To reject the registration, please click on the following link

+ +

$reject

+ + diff --git a/modules/auth/site/mail_templates/account_rejected.html b/modules/auth/site/mail_templates/account_rejected.html new file mode 100644 index 0000000..9cefb80 --- /dev/null +++ b/modules/auth/site/mail_templates/account_rejected.html @@ -0,0 +1,13 @@ + + + + + New Activation + + + + + +

You requested has been rejected, your application does not conform our rules ROC CMS

+ + \ No newline at end of file diff --git a/modules/auth/site/scripts/auth_temp_user.tpl b/modules/auth/site/scripts/auth_temp_user.tpl new file mode 100644 index 0000000..38ae29b --- /dev/null +++ b/modules/auth/site/scripts/auth_temp_user.tpl @@ -0,0 +1,13 @@ + +DROP TABLE IF EXISTS "auth_temp_user"; +CREATE TABLE `auth_temp_user` ( + `uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `name` VARCHAR(100) NOT NULL, + `password` VARCHAR(100) NOT NULL, + `salt` VARCHAR(100) NOT NULL, + `email` VARCHAR(250) NOT NULL, + `application` TEXT NOT NULL, + CONSTRAINT `name` + UNIQUE(`name`) +); + diff --git a/modules/auth/site/templates/block_post_reactivate.tpl b/modules/auth/site/templates/block_post_reactivate.tpl index 09e7206..c76cbb5 100644 --- a/modules/auth/site/templates/block_post_reactivate.tpl +++ b/modules/auth/site/templates/block_post_reactivate.tpl @@ -1,3 +1,3 @@
-

We have send you a new activation code, check your email to activate your account.

+

Thanks for your application, we will review it to activate your account.

diff --git a/modules/auth/site/templates/block_post_register.tpl b/modules/auth/site/templates/block_post_register.tpl index d59f75a..c76cbb5 100644 --- a/modules/auth/site/templates/block_post_register.tpl +++ b/modules/auth/site/templates/block_post_register.tpl @@ -1,3 +1,3 @@
-

Thanks for register, check your email to activate your account.

+

Thanks for your application, we will review it to activate your account.