diff --git a/integration/src/test/scala/org/knora/webapi/e2e/admin/UsersADME2ESpec.scala b/integration/src/test/scala/org/knora/webapi/e2e/admin/UsersADME2ESpec.scala index 0f9c2f8684..2e2ddd0932 100644 --- a/integration/src/test/scala/org/knora/webapi/e2e/admin/UsersADME2ESpec.scala +++ b/integration/src/test/scala/org/knora/webapi/e2e/admin/UsersADME2ESpec.scala @@ -296,6 +296,27 @@ class UsersADME2ESpec } "given a custom Iri" should { + "given no credentials in the request when creating a user it must be forbidden" in { + val validUserCreationRequest: String = + s"""{ + | "id": "$customUserIri", + | "username": "userWithCustomIri", + | "email": "userWithCustomIri@example.org", + | "givenName": "a user", + | "familyName": "with a custom Iri", + | "password": "test", + | "status": true, + | "lang": "en", + | "systemAdmin": false + |}""".stripMargin + val request = Post( + baseApiUrl + s"/admin/users", + HttpEntity(ContentTypes.`application/json`, validUserCreationRequest) + ) + val response: HttpResponse = singleAwaitingRequest(request) + response.status should be(StatusCodes.Forbidden) + } + "create a user with the provided custom IRI" in { val createUserWithCustomIriRequest: String = s"""{ @@ -323,7 +344,7 @@ class UsersADME2ESpec val request = Post( baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, createUserWithCustomIriRequest) - ) + ) ~> addRootUserCredentials() val response: HttpResponse = singleAwaitingRequest(request) response.status should be(StatusCodes.OK) @@ -359,7 +380,10 @@ class UsersADME2ESpec | "systemAdmin": false |}""".stripMargin - val request = Post(baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, params)) + val request = Post( + baseApiUrl + s"/admin/users", + HttpEntity(ContentTypes.`application/json`, params) + ) ~> addRootUserCredentials() val response: HttpResponse = singleAwaitingRequest(request) response.status should be(StatusCodes.BadRequest) @@ -389,7 +413,7 @@ class UsersADME2ESpec val request = Post( baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, createUserWithApostropheRequest) - ) + ) ~> addRootUserCredentials() val response: HttpResponse = singleAwaitingRequest(request) response.status should be(StatusCodes.OK) @@ -463,7 +487,11 @@ class UsersADME2ESpec text = createUserRequest ) ) - val request = Post(baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, createUserRequest)) + val request = Post( + baseApiUrl + s"/admin/users", + HttpEntity(ContentTypes.`application/json`, createUserRequest) + ) ~> addRootUserCredentials() + val response: HttpResponse = singleAwaitingRequest(request) response.status should be(StatusCodes.OK) @@ -513,7 +541,10 @@ class UsersADME2ESpec text = createUserRequest ) ) - val request = Post(baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, createUserRequest)) + val request = Post( + baseApiUrl + s"/admin/users", + HttpEntity(ContentTypes.`application/json`, createUserRequest) + ) ~> addRootUserCredentials() val response: HttpResponse = singleAwaitingRequest(request) response.status should be(StatusCodes.BadRequest) @@ -553,7 +584,10 @@ class UsersADME2ESpec text = createUserRequest ) ) - val request = Post(baseApiUrl + s"/admin/users", HttpEntity(ContentTypes.`application/json`, createUserRequest)) + val request = Post( + baseApiUrl + s"/admin/users", + HttpEntity(ContentTypes.`application/json`, createUserRequest) + ) ~> addRootUserCredentials() val response: HttpResponse = singleAwaitingRequest(request) response.status should be(StatusCodes.BadRequest) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/ApiRoutes.scala b/webapi/src/main/scala/org/knora/webapi/routing/ApiRoutes.scala index a0d835b5c0..775e32e36a 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/ApiRoutes.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/ApiRoutes.scala @@ -31,6 +31,7 @@ import org.knora.webapi.slice.admin.api.AdminApiRoutes import org.knora.webapi.slice.admin.api.ProjectsEndpointsHandler import org.knora.webapi.slice.admin.api.service.ProjectADMRestService import org.knora.webapi.slice.admin.domain.service.KnoraProjectRepo +import org.knora.webapi.slice.common.api.AuthorizationRestService import org.knora.webapi.slice.ontology.api.service.RestCardinalityService import org.knora.webapi.slice.resourceinfo.api.ResourceInfoRoutes import org.knora.webapi.slice.resourceinfo.api.service.RestResourceInfoService @@ -48,7 +49,7 @@ object ApiRoutes { * All routes composed together. */ val layer: URLayer[ - ActorSystem & AdminApiRoutes & AppConfig & AppRouter & core.State & IriConverter & KnoraProjectRepo & MessageRelay & ProjectADMRestService & ProjectsEndpointsHandler & ResourceInfoRoutes & RestCardinalityService & RestResourceInfoService & routing.Authenticator & SearchApiRoutes & SearchResponderV2 & SipiService & StringFormatter & UsersResponderADM & ValuesResponderV2, + ActorSystem & AuthorizationRestService & AdminApiRoutes & AppConfig & AppRouter & core.State & IriConverter & KnoraProjectRepo & MessageRelay & ProjectADMRestService & ProjectsEndpointsHandler & ResourceInfoRoutes & RestCardinalityService & RestResourceInfoService & routing.Authenticator & SearchApiRoutes & SearchResponderV2 & SipiService & StringFormatter & UsersResponderADM & ValuesResponderV2, ApiRoutes ] = ZLayer { @@ -62,7 +63,7 @@ object ApiRoutes { routeData <- ZIO.succeed(KnoraRouteData(sys.system, router.ref, appConfig)) runtime <- ZIO.runtime[ - AppConfig & core.State & IriConverter & KnoraProjectRepo & MessageRelay & ProjectADMRestService & RestCardinalityService & RestResourceInfoService & routing.Authenticator & SearchApiRoutes & SearchResponderV2 & SipiService & StringFormatter & UsersResponderADM & ValuesResponderV2 + AppConfig & AuthorizationRestService & core.State & IriConverter & KnoraProjectRepo & MessageRelay & ProjectADMRestService & RestCardinalityService & RestResourceInfoService & routing.Authenticator & SearchApiRoutes & SearchResponderV2 & SipiService & StringFormatter & UsersResponderADM & ValuesResponderV2 ] } yield ApiRoutesImpl(routeData, adminApiRoutes, resourceInfoRoutes, searchApiRoutes, appConfig, runtime) } @@ -82,7 +83,7 @@ private final case class ApiRoutesImpl( searchApiRoutes: SearchApiRoutes, appConfig: AppConfig, implicit val runtime: Runtime[ - AppConfig & core.State & IriConverter & KnoraProjectRepo & MessageRelay & ProjectADMRestService & RestCardinalityService & RestResourceInfoService & routing.Authenticator & SearchResponderV2 & SipiService & StringFormatter & UsersResponderADM & ValuesResponderV2 + AppConfig & AuthorizationRestService & core.State & IriConverter & KnoraProjectRepo & MessageRelay & ProjectADMRestService & RestCardinalityService & RestResourceInfoService & routing.Authenticator & SearchResponderV2 & SipiService & StringFormatter & UsersResponderADM & ValuesResponderV2 ] ) extends ApiRoutes with AroundDirectives { diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala index 29e1a15114..0e4da37e7f 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala @@ -23,12 +23,13 @@ import org.knora.webapi.routing.RouteUtilADM.getIriUserUuid import org.knora.webapi.routing.RouteUtilADM.getUserUuid import org.knora.webapi.routing.RouteUtilADM.runJsonRouteZ import org.knora.webapi.slice.admin.domain.model.* +import org.knora.webapi.slice.common.api.AuthorizationRestService /** * Provides an pekko-http-routing function for API routes that deal with users. */ final case class UsersRouteADM()( - private implicit val runtime: Runtime[Authenticator & StringFormatter & MessageRelay] + private implicit val runtime: Runtime[Authenticator & AuthorizationRestService & StringFormatter & MessageRelay] ) { private val usersBasePath: PathMatcher[Unit] = PathMatcher("admin" / "users") @@ -58,6 +59,7 @@ final case class UsersRouteADM()( val requestTask = for { payload <- UserCreatePayloadADM.make(apiRequest).mapError(BadRequestException(_)).toZIO r <- getUserUuid(ctx) + _ <- AuthorizationRestService.ensureSystemAdmin(r.user) } yield UserCreateRequestADM(payload, r.user, r.uuid) runJsonRouteZ(requestTask, ctx) }