Skip to content

Commit

Permalink
refactor: Streamline user identifier objects (DEV-3155) (#2991)
Browse files Browse the repository at this point in the history
  • Loading branch information
BalduinLandolt authored Jan 12, 2024
1 parent 98820b0 commit 0d07b6f
Show file tree
Hide file tree
Showing 22 changed files with 676 additions and 595 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,80 +137,6 @@ class UsersMessagesADMSpec extends CoreSpec {
"allow checking the password (2)" in {
SharedTestDataADM.rootUser.passwordMatch("test") should equal(true)
}

"return isSelf for IRI" in {
SharedTestDataADM.rootUser.isSelf(UserIdentifierADM(maybeIri = Some(SharedTestDataADM.rootUser.id)))
}

"return isSelf for email" in {
SharedTestDataADM.rootUser.isSelf(UserIdentifierADM(maybeEmail = Some(SharedTestDataADM.rootUser.email)))
}

"return isSelf for username" in {
SharedTestDataADM.rootUser.isSelf(UserIdentifierADM(maybeUsername = Some(SharedTestDataADM.rootUser.username)))
}
}

"The UserIdentifierADM case class" should {

"return the identifier type" in {

val iriIdentifier = UserIdentifierADM(maybeIri = Some("http://rdfh.ch/users/root"))
iriIdentifier.hasType should be(UserIdentifierType.Iri)

val emailIdentifier = UserIdentifierADM(maybeEmail = Some("[email protected]"))
emailIdentifier.hasType should be(UserIdentifierType.Email)

val usernameIdentifier = UserIdentifierADM(maybeUsername = Some("root"))
usernameIdentifier.hasType should be(UserIdentifierType.Username)
}

"check whether a user identified by email is the same as a user identified by username" in {
val userEmail = "[email protected]"
val username = "user"

val user = User(
id = "http://rdfh.ch/users/example",
username = username,
email = userEmail,
givenName = "Foo",
familyName = "Bar",
status = true,
lang = "en"
)

val emailID = UserIdentifierADM(maybeEmail = Some(userEmail))
val usernameID = UserIdentifierADM(maybeUsername = Some(username))

assert(user.isSelf(emailID))
assert(user.isSelf(usernameID))
}

"throw a BadRequestException for an empty identifier" in {
assertThrows[BadRequestException](
UserIdentifierADM()
)
}

"throw a BadRequestException for an invalid user IRI" in {
assertThrows[BadRequestException](
UserIdentifierADM(maybeIri = Some("http://example.org/not/our/user/iri/structure"))
)
}

"throw a BadRequestException for an invalid email" in {
assertThrows[BadRequestException](
UserIdentifierADM(maybeEmail = Some("invalidemail"))
)
}

"throw a BadRequestException for an invalid username" in {
assertThrows[BadRequestException](
// we allow max 50 characters in username
UserIdentifierADM(maybeEmail = Some("_username"))
)
}

}

"The ChangeUserApiRequestADM case class" should {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectMembers
import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectMembersGetResponseADM
import org.knora.webapi.messages.admin.responder.usersmessages.*
import org.knora.webapi.messages.util.KnoraSystemInstances
import org.knora.webapi.messages.v2.routing.authenticationmessages.CredentialsIdentifier
import org.knora.webapi.messages.v2.routing.authenticationmessages.KnoraCredentialsV2
import org.knora.webapi.routing.Authenticator
import org.knora.webapi.routing.UnsafeZioRun
Expand Down Expand Up @@ -89,35 +90,26 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender {

"asked about an user identified by 'iri' " should {
"return a profile if the user (root user) is known" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeIri = Some(rootUser.id)),
appActor ! UserGetByIriADM(
identifier = UserIri.unsafeFrom(rootUser.id),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Some(rootUser.ofType(UserInformationTypeADM.Full)))
}

"return a profile if the user (incunabula user) is known" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeIri = Some(incunabulaProjectAdminUser.id)),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Some(incunabulaProjectAdminUser.ofType(UserInformationTypeADM.Full)))
}

"return 'NotFoundException' when the user is unknown" in {
appActor ! UserGetRequestADM(
identifier = UserIdentifierADM(maybeIri = Some("http://rdfh.ch/users/notexisting")),
appActor ! UserGetByIriRequestADM(
identifier = UserIri.unsafeFrom("http://rdfh.ch/users/notexisting"),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Failure(NotFoundException(s"User 'http://rdfh.ch/users/notexisting' not found")))
}

"return 'None' when the user is unknown" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeIri = Some("http://rdfh.ch/users/notexisting")),
appActor ! UserGetByIriADM(
identifier = UserIri.unsafeFrom("http://rdfh.ch/users/notexisting"),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
Expand All @@ -127,35 +119,26 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender {

"asked about an user identified by 'email'" should {
"return a profile if the user (root user) is known" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeEmail = Some(rootUser.email)),
appActor ! UserGetByEmailADM(
email = Email.unsafeFrom(rootUser.email),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Some(rootUser.ofType(UserInformationTypeADM.Full)))
}

"return a profile if the user (incunabula user) is known" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeEmail = Some(incunabulaProjectAdminUser.email)),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Some(incunabulaProjectAdminUser.ofType(UserInformationTypeADM.Full)))
}

"return 'NotFoundException' when the user is unknown" in {
appActor ! UserGetRequestADM(
identifier = UserIdentifierADM(maybeEmail = Some("[email protected]")),
appActor ! UserGetByEmailRequestADM(
email = Email.unsafeFrom("[email protected]"),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Failure(NotFoundException(s"User '[email protected]' not found")))
}

"return 'None' when the user is unknown" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeEmail = Some("[email protected]")),
appActor ! UserGetByEmailADM(
email = Email.unsafeFrom("[email protected]"),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
Expand All @@ -165,35 +148,26 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender {

"asked about an user identified by 'username'" should {
"return a profile if the user (root user) is known" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeUsername = Some(rootUser.username)),
appActor ! UserGetByUsernameADM(
username = Username.unsafeFrom(rootUser.username),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Some(rootUser.ofType(UserInformationTypeADM.Full)))
}

"return a profile if the user (incunabula user) is known" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeUsername = Some(incunabulaProjectAdminUser.username)),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Some(incunabulaProjectAdminUser.ofType(UserInformationTypeADM.Full)))
}

"return 'NotFoundException' when the user is unknown" in {
appActor ! UserGetRequestADM(
identifier = UserIdentifierADM(maybeUsername = Some("userwrong")),
appActor ! UserGetByUsernameRequestADM(
username = Username.unsafeFrom("userwrong"),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
expectMsg(Failure(NotFoundException(s"User 'userwrong' not found")))
}

"return 'None' when the user is unknown" in {
appActor ! UserGetADM(
identifier = UserIdentifierADM(maybeUsername = Some("userwrong")),
appActor ! UserGetByUsernameADM(
username = Username.unsafeFrom("userwrong"),
userInformationTypeADM = UserInformationTypeADM.Full,
requestingUser = KnoraSystemInstances.Users.SystemUser
)
Expand Down Expand Up @@ -360,14 +334,9 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender {
expectMsgType[UserOperationResponseADM](timeout)

// need to be able to authenticate credentials with new password
val resF = UnsafeZioRun.runToFuture(
Authenticator.authenticateCredentialsV2(
credentials = Some(
KnoraCredentialsV2
.KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(normalUser.email)), "test123456")
)
)
)
val cedId = CredentialsIdentifier.UsernameIdentifier(Username.unsafeFrom(normalUser.username))
val credentials = KnoraCredentialsV2.KnoraPasswordCredentialsV2(cedId, "test123456")
val resF = UnsafeZioRun.runToFuture(Authenticator.authenticateCredentialsV2(Some(credentials)))

resF map { res => assert(res) }
}
Expand All @@ -389,14 +358,9 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender {
expectMsgType[UserOperationResponseADM](timeout)

// need to be able to authenticate credentials with new password
val resF = UnsafeZioRun.runToFuture(
Authenticator.authenticateCredentialsV2(
credentials = Some(
KnoraCredentialsV2
.KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(normalUser.email)), "test654321")
)
)
)
val cedId = CredentialsIdentifier.UsernameIdentifier(Username.unsafeFrom(normalUser.username))
val credentials = KnoraCredentialsV2.KnoraPasswordCredentialsV2(cedId, "test654321")
val resF = UnsafeZioRun.runToFuture(Authenticator.authenticateCredentialsV2(Some(credentials)))

resF map { res => assert(res) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,22 @@

package org.knora.webapi.routing

import org.apache.pekko
import org.apache.pekko.testkit.ImplicitSender
import org.scalatest.PrivateMethodTester
import zio.ZIO

import dsp.errors.BadCredentialsException
import dsp.errors.BadRequestException
import org.knora.webapi.*
import org.knora.webapi.messages.StringFormatter
import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM
import org.knora.webapi.messages.v2.routing.authenticationmessages.CredentialsIdentifier
import org.knora.webapi.messages.v2.routing.authenticationmessages.KnoraCredentialsV2.KnoraJWTTokenCredentialsV2
import org.knora.webapi.messages.v2.routing.authenticationmessages.KnoraCredentialsV2.KnoraPasswordCredentialsV2
import org.knora.webapi.routing.Authenticator.AUTHENTICATION_INVALIDATION_CACHE_NAME
import org.knora.webapi.sharedtestdata.SharedTestDataADM
import org.knora.webapi.slice.admin.domain.model.Email
import org.knora.webapi.slice.admin.domain.model.User
import org.knora.webapi.util.ZioScalaTestUtil.assertFailsWithA
import org.knora.webapi.util.cache.CacheUtil

import pekko.testkit.ImplicitSender

object AuthenticatorSpec {
private val rootUser = SharedTestDataADM.rootUser
private val rootUserEmail = rootUser.email
Expand All @@ -39,50 +36,35 @@ class AuthenticatorSpec extends CoreSpec with ImplicitSender with PrivateMethodT
"During Authentication" when {
"called, the 'getUserADMByEmail' method " should {
"succeed with the correct 'email' " in {
val user = UnsafeZioRun.runOrThrow(
Authenticator.getUserByIdentifier(UserIdentifierADM(maybeEmail = Some(AuthenticatorSpec.rootUserEmail)))
)
val user =
UnsafeZioRun.runOrThrow(Authenticator.getUserByEmail(Email.unsafeFrom(AuthenticatorSpec.rootUserEmail)))
assert(user == AuthenticatorSpec.rootUser)
}

"fail with the wrong 'email' " in {
val actual = UnsafeZioRun.run(
Authenticator.getUserByIdentifier(UserIdentifierADM(maybeEmail = Some("[email protected]")))
)
val actual = UnsafeZioRun.run(Authenticator.getUserByEmail(Email.unsafeFrom("[email protected]")))
assertFailsWithA[BadCredentialsException](actual)
}

"fail when not providing anything " in {
val actual = UnsafeZioRun.run(ZIO.attempt(UserIdentifierADM()))

assertFailsWithA[BadRequestException](actual)
}
}

"called, the 'authenticateCredentialsV2' method" should {
"succeed with correct email/password" in {
val correctPasswordCreds =
KnoraPasswordCredentialsV2(
UserIdentifierADM(maybeEmail = Some(AuthenticatorSpec.rootUserEmail)),
AuthenticatorSpec.rootUserPassword
)
val credId = CredentialsIdentifier.EmailIdentifier(Email.unsafeFrom(AuthenticatorSpec.rootUserEmail))
val correctPasswordCreds = KnoraPasswordCredentialsV2(credId, AuthenticatorSpec.rootUserPassword)
val isAuthenticated =
UnsafeZioRun.runOrThrow(Authenticator.authenticateCredentialsV2(Some(correctPasswordCreds)))
assert(isAuthenticated)
}
"fail with unknown email" in {
val invalidEmailCreds =
KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some("[email protected]")), "wrongpassword")
val resF = UnsafeZioRun.run(Authenticator.authenticateCredentialsV2(Some(invalidEmailCreds)))
val invalidCredId = CredentialsIdentifier.EmailIdentifier(Email.unsafeFrom("[email protected]"))
val invalidEmailCreds = KnoraPasswordCredentialsV2(invalidCredId, "wrongpassword")
val resF = UnsafeZioRun.run(Authenticator.authenticateCredentialsV2(Some(invalidEmailCreds)))
assertFailsWithA[BadCredentialsException](resF)
}
"fail with wrong password" in {
val invalidPasswordCreds =
KnoraPasswordCredentialsV2(
UserIdentifierADM(maybeEmail = Some(AuthenticatorSpec.rootUserEmail)),
"wrongpassword"
)
val actual = UnsafeZioRun.run(Authenticator.authenticateCredentialsV2(Some(invalidPasswordCreds)))
val credId = CredentialsIdentifier.EmailIdentifier(Email.unsafeFrom(AuthenticatorSpec.rootUserEmail))
val invalidPasswordCreds = KnoraPasswordCredentialsV2(credId, "wrongpassword")
val actual = UnsafeZioRun.run(Authenticator.authenticateCredentialsV2(Some(invalidPasswordCreds)))
assertFailsWithA[BadCredentialsException](actual)
}
"succeed with correct token" in {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ import dsp.errors.BadRequestException
import org.knora.webapi.*
import org.knora.webapi.messages.StringFormatter
import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM.*
import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM
import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceGetProjectADM
import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceGetUserADM
import org.knora.webapi.messages.store.cacheservicemessages.CacheServicePutProjectADM
import org.knora.webapi.messages.store.cacheservicemessages.CacheServicePutUserADM
import org.knora.webapi.messages.store.cacheservicemessages.*
import org.knora.webapi.sharedtestdata.SharedTestDataADM
import org.knora.webapi.slice.admin.domain.model.*

/**
* This spec is used to test [[org.knora.webapi.store.cache.serialization.CacheSerialization]].
Expand All @@ -34,17 +31,17 @@ class CacheServiceManagerSpec extends CoreSpec {
}

"successfully retrieve a user by IRI" in {
appActor ! CacheServiceGetUserADM(UserIdentifierADM(maybeIri = Some(user.id)))
appActor ! CacheServiceGetUserByIriADM(UserIri.unsafeFrom(user.id))
expectMsg(Some(user))
}

"successfully retrieve a user by USERNAME" in {
appActor ! CacheServiceGetUserADM(UserIdentifierADM(maybeUsername = Some(user.username)))
appActor ! CacheServiceGetUserByUsernameADM(Username.unsafeFrom(user.username))
expectMsg(Some(user))
}

"successfully retrieve a user by EMAIL" in {
appActor ! CacheServiceGetUserADM(UserIdentifierADM(maybeEmail = Some(user.email)))
appActor ! CacheServiceGetUserByEmailADM(Email.unsafeFrom(user.email))
expectMsg(Some(user))
}

Expand Down
Loading

0 comments on commit 0d07b6f

Please sign in to comment.