[SHIRO-818] Return other status codes for AuthorizationExceptions.

 - shorten the test using Apache CXF.
 - Log exceptions.
 - do not map the class AuthorizationException itself (for now).
   This exception is only thrown from the aop support (which might need to be changed to a subclass)
   and from Jdbc/Ldap-Realms. But those should lead to internal server errors, as
   internal code has thrown an exception.

Co-authored-by: Romain Manni-Bucau <rmannibucau@apache.org>
diff --git a/support/jaxrs/pom.xml b/support/jaxrs/pom.xml
index 20f6d0b..eb97308 100644
--- a/support/jaxrs/pom.xml
+++ b/support/jaxrs/pom.xml
@@ -63,6 +63,42 @@
             <version>2.3.1</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>3.4.3</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.cxf</groupId>
+                    <artifactId>cxf-rt-security</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.cxf</groupId>
+                    <artifactId>cxf-rt-transports-http</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>jakarta.xml.soap</groupId>
+                    <artifactId>jakarta.xml.soap-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.sun.activation</groupId>
+                    <artifactId>jakarta.activation</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.sun.xml.messaging.saaj</groupId>
+                    <artifactId>saaj-impl</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.jboss.spec.javax.rmi</groupId>
+                    <artifactId>jboss-rmi-api_1.0_spec</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.fasterxml.woodstox</groupId>
+                    <artifactId>woodstox-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ShiroFeature.java b/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ShiroFeature.java
index 0a4718b..4b098b7 100644
--- a/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ShiroFeature.java
+++ b/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ShiroFeature.java
@@ -18,6 +18,8 @@
  */
 package org.apache.shiro.web.jaxrs;
 
+import org.apache.shiro.authz.UnauthenticatedException;
+
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.Feature;
 import javax.ws.rs.core.FeatureContext;
@@ -25,7 +27,7 @@
 
 
 /**
- * Shiro JAX-RS feature which includes {@link ExceptionMapper}, {@link SubjectPrincipalRequestFilter}, and
+ * Shiro JAX-RS feature which includes {@link UnauthorizedExceptionExceptionMapper}, {@link SubjectPrincipalRequestFilter}, and
  * {@link ShiroAnnotationFilterFeature}.
  *
  * Typically a JAX-RS {@link Application} class will include this Feature class in the
@@ -52,7 +54,8 @@
     @Override
     public boolean configure(FeatureContext context) {
 
-        context.register(ExceptionMapper.class);
+        context.register(UnauthorizedExceptionExceptionMapper.class);
+        context.register(UnauthenticatedException.class);
         context.register(SubjectPrincipalRequestFilter.class);
         context.register(ShiroAnnotationFilterFeature.class);
 
diff --git a/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/UnauthenticatedExceptionExceptionMapper.java b/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/UnauthenticatedExceptionExceptionMapper.java
new file mode 100644
index 0000000..872bd58
--- /dev/null
+++ b/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/UnauthenticatedExceptionExceptionMapper.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.web.jaxrs;
+
+
+import org.apache.shiro.authz.UnauthenticatedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
+
+/**
+ * JAX-RS exception mapper used to map Shiro {@link UnauthenticatedException} to HTTP status codes.
+ * {@link UnauthenticatedException} will be mapped to 403.
+ * @since 1.4
+ */
+public class UnauthenticatedExceptionExceptionMapper implements ExceptionMapper<UnauthenticatedException> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UnauthenticatedExceptionExceptionMapper.class);
+
+    @Override
+    public Response toResponse(UnauthenticatedException exception) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("unauthenticated.", exception);
+        }
+
+        return Response.status(Status.FORBIDDEN).build();
+    }
+}
diff --git a/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ExceptionMapper.java b/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/UnauthorizedExceptionExceptionMapper.java
similarity index 60%
rename from support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ExceptionMapper.java
rename to support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/UnauthorizedExceptionExceptionMapper.java
index ec6fb64..d6e842b 100644
--- a/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/ExceptionMapper.java
+++ b/support/jaxrs/src/main/java/org/apache/shiro/web/jaxrs/UnauthorizedExceptionExceptionMapper.java
@@ -19,30 +19,30 @@
 package org.apache.shiro.web.jaxrs;
 
 
-import org.apache.shiro.authz.AuthorizationException;
 import org.apache.shiro.authz.UnauthorizedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.ext.ExceptionMapper;
 
 /**
- * JAX-RS exception mapper used to map Shiro {@link AuthorizationExceptions} to HTTP status codes.
- * {@link UnauthorizedException} will be mapped to 403, all others 401.
+ * JAX-RS exception mapper used to map Shiro {@link UnauthorizedException} to HTTP status codes.
+ * {@link UnauthorizedException} will be mapped to 401.
  * @since 1.4
  */
-public class ExceptionMapper implements javax.ws.rs.ext.ExceptionMapper<AuthorizationException> {
+public class UnauthorizedExceptionExceptionMapper implements ExceptionMapper<UnauthorizedException> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UnauthorizedExceptionExceptionMapper.class);
 
     @Override
-    public Response toResponse(AuthorizationException exception) {
+    public Response toResponse(UnauthorizedException exception) {
 
-        Status status;
-
-        if (exception instanceof UnauthorizedException) {
-            status = Status.FORBIDDEN;
-        } else {
-            status = Status.UNAUTHORIZED;
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("unauthenticated.", exception);
         }
 
-        return Response.status(status).build();
+        return Response.status(Status.UNAUTHORIZED).build();
     }
 }
diff --git a/support/jaxrs/src/test/groovy/org/apache/shiro/web/jaxrs/ExceptionMapperTest.groovy b/support/jaxrs/src/test/groovy/org/apache/shiro/web/jaxrs/ExceptionMapperTest.groovy
deleted file mode 100644
index f42fbd6..0000000
--- a/support/jaxrs/src/test/groovy/org/apache/shiro/web/jaxrs/ExceptionMapperTest.groovy
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.shiro.web.jaxrs
-
-import org.apache.shiro.authz.AuthorizationException
-import org.apache.shiro.authz.UnauthorizedException
-import org.junit.Test
-
-import javax.ws.rs.core.Response
-import javax.ws.rs.ext.RuntimeDelegate
-
-import static org.junit.Assert.assertSame
-import static org.mockito.Mockito.*
-
-/**
- * Tests for {@link ExceptionMapper}.
- * @since 1.4
- */
-class ExceptionMapperTest {
-
-    @Test
-    void testUnauthorizedException() {
-
-        doTest(new UnauthorizedException("expected test exception."), Response.Status.FORBIDDEN)
-        doTest(new AuthorizationException("expected test exception."), Response.Status.UNAUTHORIZED)
-        doTest(null, Response.Status.UNAUTHORIZED)
-    }
-
-    private void doTest(AuthorizationException exception , Response.StatusType expectedStatus) {
-        def runtimeDelegate = mock(RuntimeDelegate)
-
-        RuntimeDelegate.setInstance(runtimeDelegate)
-
-        def responseBuilder = mock(Response.ResponseBuilder)
-        def response = mock(Response)
-
-        when(runtimeDelegate.createResponseBuilder()).then(args -> responseBuilder)
-        when(responseBuilder.status((Response.StatusType) expectedStatus)).then(args -> responseBuilder)
-        when(responseBuilder.build()).then(args -> response)
-
-        def responseResult = new ExceptionMapper().toResponse(exception)
-        assertSame response, responseResult
-
-        verify(runtimeDelegate).createResponseBuilder()
-        verify(responseBuilder).status((Response.StatusType) expectedStatus)
-        verify(responseBuilder).build()
-    }
-}
diff --git a/support/jaxrs/src/test/groovy/org/apache/shiro/web/jaxrs/UnauthorizedExceptionExceptionMapperTest.groovy b/support/jaxrs/src/test/groovy/org/apache/shiro/web/jaxrs/UnauthorizedExceptionExceptionMapperTest.groovy
new file mode 100644
index 0000000..ef64f47
--- /dev/null
+++ b/support/jaxrs/src/test/groovy/org/apache/shiro/web/jaxrs/UnauthorizedExceptionExceptionMapperTest.groovy
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.web.jaxrs
+
+import org.apache.shiro.authz.AuthorizationException
+import org.apache.shiro.authz.HostUnauthorizedException
+import org.apache.shiro.authz.UnauthenticatedException
+import org.apache.shiro.authz.UnauthorizedException
+import org.junit.Test
+
+import javax.ws.rs.core.Response
+import javax.ws.rs.ext.ExceptionMapper
+
+import static org.junit.Assert.assertEquals
+
+/**
+ * Tests for {@link UnauthorizedExceptionExceptionMapper}.
+ * @since 1.4
+ */
+class UnauthorizedExceptionExceptionMapperTest {
+
+    @Test
+    void testUnauthorizedException() {
+        doTest(new UnauthorizedException("expected test exception."), Response.Status.UNAUTHORIZED, new UnauthorizedExceptionExceptionMapper())
+        doTest(new HostUnauthorizedException("expected test exception."), Response.Status.UNAUTHORIZED, new UnauthorizedExceptionExceptionMapper())
+        doTest(new UnauthenticatedException("expected test exception."), Response.Status.FORBIDDEN, new UnauthenticatedExceptionExceptionMapper())
+    }
+
+    private static void doTest(AuthorizationException exception , Response.StatusType expectedStatus, ExceptionMapper<? extends Throwable> exceptionMapper) {
+        final var response = exceptionMapper.toResponse(exception);
+        assertEquals(expectedStatus.statusCode, response.status);
+    }
+}