Repository: ls1intum/artemis
Issue: Outdated activation links shouldn't cause a full stracktrace in server logs

### Describe the bug

Clicking outdated activation links lead to an internal server error with full stacktrace in the server logs and make me, as a server admin, think that something really bad has happened (i.e., sth that needs further investigation).

### To Reproduce

1. Go to `/account/activate?key=foo`.
2. Check the server logs and see an *Internal Server Error* in from `o.z.problem.spring.common.AdviceTraits`.

### Expected behavior

There should be only an `INFO` log line mentioning that the activation key XYZ was not found or is otherwise invalid.

### Screenshots

_No response_

### Which version of Artemis are you seeing the problem on?

6.2.1

### What browsers are you seeing the problem on?

Firefox

### Additional context

_No response_

### Relevant log output

```shell
2023-06-08 12:14:16.223 ERROR 264042 --- [.1-8080-exec-68] o.z.problem.spring.common.AdviceTraits   : Internal Server Error
de.tum.in.www1.artemis.web.rest.errors.InternalServerErrorException: No user was found for this activation key
        at de.tum.in.www1.artemis.web.rest.AccountResource.activateAccount(AccountResource.java:116)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:497)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:584)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:111)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at de.tum.in.www1.artemis.config.ApiVersionFilter.doFilter(ApiVersionFilter.java:51)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at io.sentry.spring.SentryUserFilter.doFilterInternal(SentryUserFilter.java:56)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at de.tum.in.www1.artemis.security.jwt.JWTFilter.doFilter(JWTFilter.java:36)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at de.tum.in.www1.artemis.security.lti.Lti13LaunchFilter.doFilterInternal(Lti13LaunchFilter.java:51)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at uk.ac.ox.ctl.lti13.security.oauth2.client.lti.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:147)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
        at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
...
```


Changed files:
src/test/java/de/tum/in/www1/artemis/user/AccountResourceWithGitLabIntegrationTest.java
src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicAccountResource.java
src/test/java/de/tum/in/www1/artemis/user/AccountResourceIntegrationTest.java

diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicAccountResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicAccountResource.java
index 75fa9cd1af..0db3d9347f 100644
--- a/src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicAccountResource.java
+++ b/src/main/java/de/tum/in/www1/artemis/web/rest/open/PublicAccountResource.java
@@ -34,7 +34,6 @@ import de.tum.in.www1.artemis.web.rest.errors.AccessForbiddenException;
 import de.tum.in.www1.artemis.web.rest.errors.BadRequestAlertException;
 import de.tum.in.www1.artemis.web.rest.errors.EmailAlreadyUsedException;
 import de.tum.in.www1.artemis.web.rest.errors.EntityNotFoundException;
-import de.tum.in.www1.artemis.web.rest.errors.InternalServerErrorException;
 import de.tum.in.www1.artemis.web.rest.errors.LoginAlreadyUsedException;
 import de.tum.in.www1.artemis.web.rest.errors.PasswordViolatesRequirementsException;
 import de.tum.in.www1.artemis.web.rest.vm.KeyAndPasswordVM;
@@ -104,7 +103,8 @@ public class PublicAccountResource {
      * {@code GET /activate} : activate the registered user.
      *
      * @param key the activation key.
-     * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be activated.
+     * @throws AccessForbiddenException {@code 403 (Forbidden)} if the user registration is disabled
+     * @throws EntityNotFoundException {@code 404 (Not Found)} if the user provided an invalid activation key
      */
     @GetMapping("activate")
     @EnforceNothing
@@ -114,7 +114,7 @@ public class PublicAccountResource {
         }
         Optional<User> user = userService.activateRegistration(key);
         if (user.isEmpty()) {
-            throw new InternalServerErrorException("No user was found for this activation key");
+            throw new EntityNotFoundException("Activation key", key);
         }
     }
 
diff --git a/src/test/java/de/tum/in/www1/artemis/user/AccountResourceIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/user/AccountResourceIntegrationTest.java
index 3196f743ef..3ab808db34 100644
--- a/src/test/java/de/tum/in/www1/artemis/user/AccountResourceIntegrationTest.java
+++ b/src/test/java/de/tum/in/www1/artemis/user/AccountResourceIntegrationTest.java
@@ -224,7 +224,7 @@ class AccountResourceIntegrationTest extends AbstractSpringIntegrationBambooBitb
     void activateAccountNoUser() throws Exception {
         LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>();
         params.add("key", "");
-        request.get("/api/public/activate", HttpStatus.INTERNAL_SERVER_ERROR, String.class, params);
+        request.get("/api/public/activate", HttpStatus.NOT_FOUND, String.class, params);
     }
 
     @Test
diff --git a/src/test/java/de/tum/in/www1/artemis/user/AccountResourceWithGitLabIntegrationTest.java b/src/test/java/de/tum/in/www1/artemis/user/AccountResourceWithGitLabIntegrationTest.java
index d6408dd9f0..638b475273 100644
--- a/src/test/java/de/tum/in/www1/artemis/user/AccountResourceWithGitLabIntegrationTest.java
+++ b/src/test/java/de/tum/in/www1/artemis/user/AccountResourceWithGitLabIntegrationTest.java
@@ -247,7 +247,7 @@ class AccountResourceWithGitLabIntegrationTest extends AbstractSpringIntegration
         // Activate the user
         gitlabRequestMockProvider.mockActivateUser(user.getLogin(), true);
         String activationKey = registeredUser.get().getActivationKey();
-        request.get("/api/public/activate?key=" + activationKey, HttpStatus.INTERNAL_SERVER_ERROR, Void.class);
+        request.get("/api/public/activate?key=" + activationKey, HttpStatus.NOT_FOUND, Void.class);
         verify(gitlabRequestMockProvider.getMockedUserApi()).unblockUser(anyLong());
 
         assertThat(registeredUser.get().getActivationKey()).isNotNull();