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
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ThisBuild / organization := "app.softnetwork"

name := "account"

ThisBuild / version := "0.8.7"
ThisBuild / version := "0.8.8"

ThisBuild / scalaVersion := scala212

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ object AccountSettings extends StrictLogging {

val Realm: String = config.getString("auth.realm")

/** Session key holding the account's e-mail, stamped at sign-in by every authentication path.
*
* Downstream services derive trust decisions from the e-mail DOMAIN — the licence server keys
* its one-evaluation-per-organisation rule and its free-mail gate on it. Their only other source
* is an organisation contact address the requester can edit, i.e. forge. Putting the address
* here places it behind the session's HMAC, which is the same trust the `admin` flag already
* relies on for authorization.
*
* Not a config value: it is a wire contract with those readers, so it must not be re-mappable
* per deployment. Absent for an account registered by phone (`Account.email` is an `Option`) —
* readers must handle that rather than assume presence.
*/
val SessionEmailKey: String = "email"

val Path: String = config.getString("auth.path")

val BaseUrl: String = config.getString("auth.baseUrl")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ trait AccountService[PV <: ProfileView, DV <: AccountDetailsView, AV <: AccountV
session += (session.profileKey, profile.name)
case _ =>
}
account.email match {
case Some(email) => session += (AccountSettings.SessionEmailKey, email)
case _ =>
}
setSession(sc, st, session) {
// create a new anti csrf token
setNewCsrfToken(checkHeader) {
Expand Down Expand Up @@ -224,6 +228,10 @@ trait AccountService[PV <: ProfileView, DV <: AccountDetailsView, AV <: AccountV
session += (session.profileKey, profile.name)
case _ =>
}
account.email match {
case Some(email) => session += (AccountSettings.SessionEmailKey, email)
case _ =>
}
setSession(sc, st, session) {
// create a new anti csrf token
setNewCsrfToken(checkHeader) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ trait AccountServiceEndpoints[SU, SD <: SessionData with SessionDataDecorator[SD
session += (session.profileKey, profile.name)
case _ =>
}
account.email match {
case Some(email) => session += (AccountSettings.SessionEmailKey, email)
case _ =>
}
Right((account.view.asInstanceOf[AV], Some(session)))
case other => Left(resultToApiError(other))
}
Expand Down Expand Up @@ -313,6 +317,10 @@ trait AccountServiceEndpoints[SU, SD <: SessionData with SessionDataDecorator[SD
session += (session.profileKey, profile.name)
case _ =>
}
account.email match {
case Some(email) => session += (AccountSettings.SessionEmailKey, email)
case _ =>
}
Right(
(
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ trait OAuthService[SD <: SessionData with SessionDataDecorator[SD]]
session += (session.profileKey, profile.name)
case _ =>
}
account.email match {
case Some(email) => session += (AccountSettings.SessionEmailKey, email)
case _ =>
}
setSession(sc, st, session) {
// create a new anti csrf token
setNewCsrfToken(checkHeader) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ trait OAuthServiceEndpoints[SD <: SessionData with SessionDataDecorator[SD]]
session += (session.profileKey, profile.name)
case _ =>
}
account.email match {
case Some(email) => session += (AccountSettings.SessionEmailKey, email)
case _ =>
}
Right(
account.details
.map(d => Me(d.firstName, d.lastName, d.email))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,24 @@ trait AccountRouteSpec[
responseAs[AV].status shouldBe AccountStatus.Active
}
}
// Downstream services key trust decisions on the DOMAIN of this address — the licence server
// decides one-evaluation-per-organisation and its free-mail gate on it. Their only other source
// is an organisation contact the requester can edit, i.e. forge, so the stamp is a contract
// rather than a convenience. It is asserted at the SESSION because an authentication path that
// forgets it degrades silently: the reader just falls back.
// (The e-mail account is activated by "work with matching email and password" above.)
"stamp the account e-mail into the session" in {
// No trailing signOut(): `signIn` opens with one, and calling it twice leaves stale
// headers that make the NEXT sign-in 403.
signIn(email, password)
extractSession().flatMap(_.get(AccountSettings.SessionEmailKey)) shouldBe Some(email)
}
// `Account.email` is an Option — an account registered by phone has none. The key must then be
// ABSENT rather than empty, so a reader can tell "no address" from "an address we lost".
"leave the e-mail absent for an account that has none" in {
signIn(gsm, password)
extractSession().flatMap(_.get(AccountSettings.SessionEmailKey)) shouldBe None
}
"fail with unknown username" in {
Post(
s"/$RootPath/${AccountSettings.Path}/login",
Expand Down
Loading