Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions code/src/com/sixsq/nuvla/auth/utils.clj
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,14 @@
:claims
(filter #(str/starts-with? % "session/"))
first))

(defn request-as-user
[request]
(let [user-id (current-user-id request)
active-claim (current-active-claim request)]
(if (and
(str/starts-with? active-claim "group/")
(not (#{"group/nuvla-admin" "group/nuvla-user" "group/nuvla-anon"} active-claim)))
(update request :nuvla/authn merge {:active-claim user-id
:claims #{user-id "group/nuvla-user" "group/nuvla-anon"}})
request)))
9 changes: 8 additions & 1 deletion code/src/com/sixsq/nuvla/server/resources/callback/utils.clj
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
(ns com.sixsq.nuvla.server.resources.callback.utils
(:require
[clojure.string :as str]
[com.sixsq.nuvla.db.impl :as db]
[com.sixsq.nuvla.server.resources.common.crud :as crud]
[com.sixsq.nuvla.server.resources.common.utils :as u]))
[com.sixsq.nuvla.server.resources.common.utils :as u]
[com.sixsq.nuvla.server.util.general :as gen-util]))


(defn executable?
Expand Down Expand Up @@ -37,3 +39,8 @@
db/edit)
(catch Exception e
(or (ex-data e) (throw e)))))

(defn callback-ui-url
[callback-url]
(let [base-uri (first (str/split callback-url #"api/callback"))]
(str base-uri "ui/callback?callback-url=" (gen-util/encode-uri-component callback-url))))
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ visited, the email identifier is marked as validated.
[com.sixsq.nuvla.server.resources.common.std-crud :as std-crud]
[com.sixsq.nuvla.server.resources.common.utils :as u]
[com.sixsq.nuvla.server.resources.credential-hashed-password :as hashed-password]
[com.sixsq.nuvla.server.resources.email.utils :as email-utils]
[com.sixsq.nuvla.server.resources.user-template :as p]
[com.sixsq.nuvla.server.resources.user-template-minimum :as user-minimum]
[com.sixsq.nuvla.server.resources.user.utils :as user-utils]
Expand Down Expand Up @@ -57,6 +58,7 @@ visited, the email identifier is marked as validated.
[{callback-id :id
{existing-user-id :user-id
email :email
inviter-email :inviter-email
redirect-url :redirect-url} :data
{group-id :href} :target-resource :as _callback-resource}
{{:keys [new-password]} :body :as _request}]
Expand All @@ -67,6 +69,8 @@ visited, the email identifier is marked as validated.
msg (format "'%s' successfully joined '%s'" user-id group-id)]
(add-user-to-group group-id user-id)
(utils/callback-succeeded! callback-id)
(when inviter-email
(email-utils/send-group-invitation-accepted group-id email inviter-email))
(if (and existing-user-id redirect-url)
(r/map-response msg 303 callback-id redirect-url)
(r/map-response msg 200)))
Expand Down
2 changes: 2 additions & 0 deletions code/src/com/sixsq/nuvla/server/resources/email.clj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ address. When the callback is triggered, the `validated` flag is set to true.
[com.sixsq.nuvla.server.resources.common.std-crud :as std-crud]
[com.sixsq.nuvla.server.resources.common.utils :as u]
[com.sixsq.nuvla.server.resources.email.utils :as email-utils]
[com.sixsq.nuvla.server.resources.callback.utils :as callback-utils]
[com.sixsq.nuvla.server.resources.resource-metadata :as md]
[com.sixsq.nuvla.server.resources.spec.email :as email]
[com.sixsq.nuvla.server.util.metadata :as gen-md]
Expand Down Expand Up @@ -131,6 +132,7 @@ address. When the callback is triggered, the `validated` flag is set to true.
(if-not validated
(try
(-> (email-utils/create-callback id base-uri)
callback-utils/callback-ui-url
(email-utils/send-validation-email address))
(r/map-response "check your mailbox for a validation message" 202)
(catch Exception e
Expand Down
171 changes: 70 additions & 101 deletions code/src/com/sixsq/nuvla/server/resources/email/utils.clj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,37 @@
[com.sixsq.nuvla.server.resources.email.sending :as sending]
[com.sixsq.nuvla.server.util.response :as r]))

(defn send-email
[address generate-subject-fn generate-body-fn data]
(let [{:keys [smtp-username] :as nuvla-config} (crud/retrieve-by-id-as-admin config-nuvla/config-instance-url)
data (merge data (select-keys nuvla-config [:smtp-username :conditions-url :email-header-img-url]))
subject (generate-subject-fn nuvla-config data)
body (generate-body-fn nuvla-config data)
msg {:from (or smtp-username "administrator")
:to [address]
:subject subject
:body body}]
(sending/dispatch nuvla-config msg)))

(defn create-callback [email-id base-uri]
(let [callback-request {:params {:resource-name callback/resource-type}
:body {:action email-callback/action-name
:target-resource {:href email-id}}
:nuvla/authn auth/internal-identity}

{{:keys [resource-id]} :body status :status} (crud/add callback-request)]
(if (= 201 status)
(if-let [callback-resource (crud/set-operations
(crud/retrieve-by-id-as-admin resource-id) {})]
(if-let [validate-op (u/get-op callback-resource "execute")]
(str base-uri validate-op)
(let [msg "callback does not have execute operation"]
(throw (ex-info msg (r/map-response msg 500 resource-id)))))
(let [msg "cannot retrieve email validation callback"]
(throw (ex-info msg (r/map-response msg 500 resource-id)))))
(let [msg "cannot create email validation callback"]
(throw (ex-info msg (r/map-response msg 500 email-id)))))))

(def warning-initiate
(str/join "\n"
["If you didn't initiate this request, do NOT click on any link and report"
Expand All @@ -23,7 +54,7 @@
"\n %s\n"])))

(defn validation-email-body
[callback-url conditions-url email-header-img-url]
[{:keys [conditions-url email-header-img-url] :as _nuvla-config} {:keys [callback-url] :as _data}]
[:alternative
{:type "text/plain"
:content (cond-> (format
Expand All @@ -44,79 +75,27 @@


(defn invitation-email-body
[name set-password-url conditions-url email-header-img-url]
[{:keys [conditions-url email-header-img-url] :as _nuvla-config} {:keys [name-or-id set-password-url] :as _data}]
[:alternative
{:type "text/plain"
:content (cond-> (format (str/join "\n"
["You have been invited by \"%s\" to use Nuvla."
" To accept the invitation, follow this link:"
"\n %s\n"]) name set-password-url)
"\n %s\n"]) name-or-id set-password-url)
conditions-url (str (conditions-acceptance conditions-url)))}
{:type "text/html; charset=utf-8"
:content (sending/render-content
{:title "Nuvla invitation"
:button-text "Accept invitation"
:button-url set-password-url
:text-1 (str
(format "You have been invited by \"%s\" to use Nuvla. " name)
(format "You have been invited by \"%s\" to use Nuvla. " name-or-id)
"To accept the invitation, click the following button:")
:conditions-url conditions-url
:header-img email-header-img-url})}])


(defn create-callback [email-id base-uri]
(let [callback-request {:params {:resource-name callback/resource-type}
:body {:action email-callback/action-name
:target-resource {:href email-id}}
:nuvla/authn auth/internal-identity}

{{:keys [resource-id]} :body status :status} (crud/add callback-request)]
(if (= 201 status)
(if-let [callback-resource (crud/set-operations
(crud/retrieve-by-id-as-admin resource-id) {})]
(if-let [validate-op (u/get-op callback-resource "execute")]
(str base-uri validate-op)
(let [msg "callback does not have execute operation"]
(throw (ex-info msg (r/map-response msg 500 resource-id)))))
(let [msg "cannot retrieve email validation callback"]
(throw (ex-info msg (r/map-response msg 500 resource-id)))))
(let [msg "cannot create email validation callback"]
(throw (ex-info msg (r/map-response msg 500 email-id)))))))


(defn send-validation-email
[callback-url address]
(let [{:keys [smtp-username conditions-url email-header-img-url]
:as nuvla-config} (crud/retrieve-by-id-as-admin config-nuvla/config-instance-url)

body (validation-email-body callback-url conditions-url email-header-img-url)

msg {:from (or smtp-username "administrator")
:to [address]
:subject "Validation email for Nuvla service"
:body body}]

(sending/dispatch nuvla-config msg)))


(defn send-invitation-email
[set-password-url address {:keys [name id] :as _user}]
(let [{:keys [smtp-username conditions-url email-header-img-url]
:as nuvla-config} (crud/retrieve-by-id-as-admin config-nuvla/config-instance-url)

body (invitation-email-body (or name id) set-password-url
conditions-url email-header-img-url)

msg {:from (or smtp-username "administrator")
:to [address]
:subject "Invitation by email for Nuvla service"
:body body}]

(sending/dispatch nuvla-config msg)))


(defn password-set-email-body
[set-password-url email-header-img-url]
[{:keys [email-header-img-url] :as _nuvla-config} {:keys [set-password-url] :as _data}]
[:alternative
{:type "text/plain"
:content (format
Expand All @@ -134,9 +113,8 @@
:warning-initiate true
:header-img email-header-img-url})}])


(defn email-token-2fa
[token email-header-img-url]
(defn email-token-2fa-body
[{:keys [email-header-img-url] :as _nuvla-config} {:keys [token] :as _data}]
[:alternative
{:type "text/plain"
:content (format
Expand All @@ -153,9 +131,8 @@
:warning-initiate true
:header-img email-header-img-url})}])


(defn join-group-email-body
[group invited-by callback-url conditions-url email-header-img-url]
[{:keys [conditions-url email-header-img-url] :as _nuvla-config} {:keys [group invited-by callback-url] :as _data}]
(let [msg (format "You have been invited by \"%s\" to join \"%s\" on Nuvla. " invited-by group)
note "Note that you will be visible to all current and future members of this group. "]
[:alternative
Expand All @@ -180,52 +157,44 @@
:conditions-url conditions-url
:header-img email-header-img-url})}]))

(defn group-invitation-email-body
[{:keys [email-header-img-url] :as _nuvla-config} {:keys [group invited-email] :as _data}]
(let [msg (format "Your invitation to group %s has been accepted by %s." group invited-email)]
[:alternative
{:type "text/plain"
:content msg}
{:type "text/html; charset=utf-8"
:content (sending/render-content
{:title (format "Invitation to group %s has been accepted" group)
:text-1 msg
:header-img email-header-img-url})}]))

(defn send-password-set-email
[set-password-url address]
(let [{:keys [smtp-username email-header-img-url]
:as nuvla-config} (crud/retrieve-by-id-as-admin
config-nuvla/config-instance-url)

body (password-set-email-body set-password-url email-header-img-url)

msg {:from (or smtp-username "administrator")
:to [address]
:subject "Set password for Nuvla service"
:body body}]
(defn send-validation-email
[callback-url address]
(send-email address (constantly "Validation email for Nuvla service")
validation-email-body {:callback-url callback-url}))

(sending/dispatch nuvla-config msg)))
(defn send-invitation-email
[set-password-url address {:keys [name id] :as _user}]
(send-email address (constantly "Invitation by email for Nuvla service")
invitation-email-body {:name-or-id (or name id)
:set-password-url set-password-url}))

(defn send-password-set-email
[set-password-url address]
(send-email address (constantly "Set password for Nuvla service")
password-set-email-body {:set-password-url set-password-url}))

(defn send-join-group-email
[group invited-by callback-url address]
(let [{:keys [smtp-username conditions-url email-header-img-url]
:as nuvla-config} (crud/retrieve-by-id-as-admin
config-nuvla/config-instance-url)

body (join-group-email-body group invited-by callback-url
conditions-url email-header-img-url)

msg {:from (or smtp-username "administrator")
:to [address]
:subject (format "You’re invited to join %s" group)
:body body}]

(sending/dispatch nuvla-config msg)))
(send-email address (fn [_ {:keys [group] :as _data}] (format "You’re invited to join %s" group))
join-group-email-body {:group group :invited-by invited-by :callback-url callback-url}))

(defn send-group-invitation-accepted
[group invited-email address]
(send-email address (fn [_ {:keys [group] :as _data}] (format "Invitation to group %s has been accepted" group))
group-invitation-email-body {:group group :invited-email invited-email}))

(defn send-email-token-2fa
[token address]
(let [{:keys [smtp-username email-header-img-url]
:as nuvla-config} (crud/retrieve-by-id-as-admin
config-nuvla/config-instance-url)

body (email-token-2fa token email-header-img-url)

msg {:from (or smtp-username "administrator")
:to [address]
:subject "Nuvla authorization code"
:body body}]

(sending/dispatch nuvla-config msg)))

(send-email address (constantly "Nuvla authorization code") email-token-2fa-body {:token token}))
Loading
Loading