[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);
+ }
+}