diff --git a/bundles/org.openhab.core.io.rest.auth/bnd.bnd b/bundles/org.openhab.core.io.rest.auth/bnd.bnd deleted file mode 100644 index e8153ce34..000000000 --- a/bundles/org.openhab.core.io.rest.auth/bnd.bnd +++ /dev/null @@ -1,2 +0,0 @@ -Bundle-SymbolicName: ${project.artifactId} -Bundle-Activator: org.openhab.core.io.rest.auth.internal.Activator diff --git a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/Activator.java b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/Activator.java deleted file mode 100644 index 46829bc04..000000000 --- a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/Activator.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2010-2020 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.core.io.rest.auth.internal; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -/** - * Registers dynamic features contained in this bundle. - * - * @author Yannick Schaus - initial contribution - */ -public class Activator implements BundleActivator { - private static Activator instance; - - private ServiceRegistration rolesAllowedDynamicFeatureRegistration; - - public static Activator getInstance() { - return instance; - } - - @Override - public void start(BundleContext context) throws Exception { - rolesAllowedDynamicFeatureRegistration = context.registerService(RolesAllowedDynamicFeatureImpl.class.getName(), - new RolesAllowedDynamicFeatureImpl(), null); - } - - @Override - public void stop(BundleContext context) throws Exception { - instance = null; - if (rolesAllowedDynamicFeatureRegistration != null) { - rolesAllowedDynamicFeatureRegistration.unregister(); - } - } -} diff --git a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/AuthFilter.java b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/AuthFilter.java index 13a63367b..6d1a24a1f 100644 --- a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/AuthFilter.java +++ b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/AuthFilter.java @@ -16,18 +16,23 @@ import java.io.IOException; import javax.annotation.Priority; import javax.security.sasl.AuthenticationException; -import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.Priorities; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.ext.Provider; import org.openhab.core.auth.Authentication; +import org.openhab.core.io.rest.JSONResponse; +import org.openhab.core.io.rest.RESTConstants; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsExtension; /** * This filter is responsible for parsing a token provided with a request, and hydrating a {@link SecurityContext} from @@ -36,9 +41,11 @@ import org.osgi.service.component.annotations.Reference; * @author Yannick Schaus - initial contribution */ @PreMatching +@Component +@JaxrsExtension +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") @Priority(Priorities.AUTHENTICATION) @Provider -@Component(immediate = true, service = AuthFilter.class) public class AuthFilter implements ContainerRequestFilter { private static final String COOKIE_AUTH_HEADER = "X-OPENHAB-AUTH-HEADER"; private static final String ALT_AUTH_HEADER = "X-OPENHAB-TOKEN"; @@ -81,7 +88,7 @@ public class AuthFilter implements ContainerRequestFilter { } } } catch (AuthenticationException e) { - throw new NotAuthorizedException("Invalid token"); + requestContext.abortWith(JSONResponse.createErrorResponse(Status.UNAUTHORIZED, "Invalid token")); } } } diff --git a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/RolesAllowedDynamicFeatureImpl.java b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/RolesAllowedDynamicFeatureImpl.java index e3a7132c9..9fdd62dc0 100644 --- a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/RolesAllowedDynamicFeatureImpl.java +++ b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/RolesAllowedDynamicFeatureImpl.java @@ -22,17 +22,22 @@ import javax.annotation.Priority; import javax.annotation.security.DenyAll; import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; -import javax.ws.rs.ForbiddenException; -import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.Priorities; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.DynamicFeature; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.FeatureContext; +import javax.ws.rs.core.Response.Status; import javax.ws.rs.ext.Provider; import org.openhab.core.auth.Role; +import org.openhab.core.io.rest.JSONResponse; +import org.openhab.core.io.rest.RESTConstants; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect; +import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,6 +53,9 @@ import org.slf4j.LoggerFactory; * @author Yannick Schaus - port to openHAB with modifications */ @Provider +@Component +@JaxrsExtension +@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")") public class RolesAllowedDynamicFeatureImpl implements DynamicFeature { private final Logger logger = LoggerFactory.getLogger(RolesAllowedDynamicFeatureImpl.class); @@ -114,7 +122,9 @@ public class RolesAllowedDynamicFeatureImpl implements DynamicFeature { } if (rolesAllowed.length > 0 && !isAuthenticated(requestContext)) { - throw new NotAuthorizedException("User is not authenticated"); + requestContext.abortWith( + JSONResponse.createErrorResponse(Status.UNAUTHORIZED, "User is not authenticated")); + return; } for (final String role : rolesAllowed) { @@ -124,7 +134,8 @@ public class RolesAllowedDynamicFeatureImpl implements DynamicFeature { } } - throw new ForbiddenException("User is authenticated but doesn't have access to this resource"); + requestContext.abortWith(JSONResponse.createErrorResponse(Status.FORBIDDEN, + "User is authenticated but doesn't have access to this resource")); } private static boolean isAuthenticated(final ContainerRequestContext requestContext) { diff --git a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/TokenResource.java b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/TokenResource.java index 6f2b54cc3..134c8bdf7 100644 --- a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/TokenResource.java +++ b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/TokenResource.java @@ -24,8 +24,6 @@ import javax.ws.rs.Consumes; import javax.ws.rs.CookieParam; import javax.ws.rs.FormParam; import javax.ws.rs.GET; -import javax.ws.rs.NotAuthorizedException; -import javax.ws.rs.NotFoundException; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; @@ -47,6 +45,7 @@ import org.openhab.core.auth.PendingToken; import org.openhab.core.auth.User; import org.openhab.core.auth.UserRegistry; import org.openhab.core.auth.UserSession; +import org.openhab.core.io.rest.JSONResponse; import org.openhab.core.io.rest.RESTConstants; import org.openhab.core.io.rest.RESTResource; import org.openhab.core.io.rest.Stream2JSONInputStream; @@ -141,12 +140,12 @@ public class TokenResource implements RESTResource { @Produces({ MediaType.APPLICATION_JSON }) public Response getSessions(@Context SecurityContext securityContext) { if (securityContext.getUserPrincipal() == null) { - throw new NotAuthorizedException("User not authenticated"); + return JSONResponse.createErrorResponse(Status.UNAUTHORIZED, "User is not authenticated"); } ManagedUser user = (ManagedUser) userRegistry.get(securityContext.getUserPrincipal().getName()); if (user == null) { - throw new NotFoundException("User not found"); + return JSONResponse.createErrorResponse(Status.NOT_FOUND, "User not found"); } Stream sessions = user.getSessions().stream().map(this::toUserSessionDTO); @@ -161,12 +160,12 @@ public class TokenResource implements RESTResource { public Response deleteSession(@FormParam("refresh_token") String refreshToken, @FormParam("id") String id, @Context SecurityContext securityContext) { if (securityContext.getUserPrincipal() == null) { - throw new NotAuthorizedException("User not authenticated"); + return JSONResponse.createErrorResponse(Status.UNAUTHORIZED, "User is not authenticated"); } ManagedUser user = (ManagedUser) userRegistry.get(securityContext.getUserPrincipal().getName()); if (user == null) { - throw new NotFoundException("User not found"); + return JSONResponse.createErrorResponse(Status.NOT_FOUND, "User not found"); } Optional session; @@ -178,7 +177,7 @@ public class TokenResource implements RESTResource { throw new IllegalArgumentException("no refresh_token or id specified"); } if (session.isEmpty()) { - throw new NotFoundException("Session not found"); + return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Session not found"); } ResponseBuilder response = Response.ok();