From c79f1d6ae6ce063644f74e89bb9c329a19a279c3 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Wed, 26 Jul 2017 15:15:20 +0200 Subject: [PATCH] [Fix] Returning 401 if session is invalid, 403 for privilege --- .../DefaultStrolchPrivilegeHandler.java | 3 +- .../StrolchNotAuthenticatedException.java | 32 ++++++++++++++ .../base/NotAuthenticatedException.java | 44 +++++++++++++++++++ .../handler/DefaultPrivilegeHandler.java | 10 +++-- .../privilege/handler/PrivilegeHandler.java | 10 ++++- .../rest/DefaultStrolchSessionHandler.java | 20 +++++---- .../strolch/rest/StrolchSessionHandler.java | 5 ++- .../filters/AuthenticationRequestFilter.java | 13 +++++- 8 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 li.strolch.model/src/main/java/li/strolch/exception/StrolchNotAuthenticatedException.java create mode 100644 li.strolch.privilege/src/main/java/li/strolch/privilege/base/NotAuthenticatedException.java diff --git a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/DefaultStrolchPrivilegeHandler.java b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/DefaultStrolchPrivilegeHandler.java index 3c48c0428..e93da3510 100644 --- a/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/DefaultStrolchPrivilegeHandler.java +++ b/li.strolch.agent/src/main/java/li/strolch/runtime/privilege/DefaultStrolchPrivilegeHandler.java @@ -30,6 +30,7 @@ import li.strolch.agent.api.StrolchRealm; import li.strolch.model.audit.AccessType; import li.strolch.model.audit.Audit; import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.privilege.base.NotAuthenticatedException; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.handler.DefaultPrivilegeHandler; import li.strolch.privilege.handler.EncryptionHandler; @@ -141,7 +142,7 @@ public class DefaultStrolchPrivilegeHandler extends StrolchComponent implements } @Override - public void isCertificateValid(Certificate certificate) throws PrivilegeException { + public void isCertificateValid(Certificate certificate) throws PrivilegeException, NotAuthenticatedException { assertStarted(); this.privilegeHandler.isCertificateValid(certificate); } diff --git a/li.strolch.model/src/main/java/li/strolch/exception/StrolchNotAuthenticatedException.java b/li.strolch.model/src/main/java/li/strolch/exception/StrolchNotAuthenticatedException.java new file mode 100644 index 000000000..6079aaab8 --- /dev/null +++ b/li.strolch.model/src/main/java/li/strolch/exception/StrolchNotAuthenticatedException.java @@ -0,0 +1,32 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed 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 li.strolch.exception; + +/** + * @author Robert von Burg + */ +public class StrolchNotAuthenticatedException extends StrolchException { + + private static final long serialVersionUID = 1L; + + public StrolchNotAuthenticatedException(String message) { + super(message); + } + + public StrolchNotAuthenticatedException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/base/NotAuthenticatedException.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/NotAuthenticatedException.java new file mode 100644 index 000000000..8a0c26006 --- /dev/null +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/base/NotAuthenticatedException.java @@ -0,0 +1,44 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed 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 li.strolch.privilege.base; + +/** + * Exception thrown if user is not authenticated, i.e. certificate is not valid anymore, etc. + * + * @author Robert von Burg + */ +public class NotAuthenticatedException extends PrivilegeException { + + private static final long serialVersionUID = 1L; + + /** + * @param msg + * detail on why and where access was denied + */ + public NotAuthenticatedException(String msg) { + super(msg); + } + + /** + * @param msg + * detail on why and where access was denied + * @param e + * root exception + */ + public NotAuthenticatedException(String msg, Exception e) { + super(msg, e); + } +} diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultPrivilegeHandler.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultPrivilegeHandler.java index 6d9a7a43e..212904019 100644 --- a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultPrivilegeHandler.java +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/DefaultPrivilegeHandler.java @@ -44,6 +44,7 @@ import org.slf4j.LoggerFactory; import li.strolch.privilege.base.AccessDeniedException; import li.strolch.privilege.base.InvalidCredentialsException; +import li.strolch.privilege.base.NotAuthenticatedException; import li.strolch.privilege.base.PrivilegeConflictResolution; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.model.Certificate; @@ -1389,7 +1390,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { } @Override - public void isCertificateValid(Certificate certificate) { + public void isCertificateValid(Certificate certificate) throws PrivilegeException, NotAuthenticatedException { // certificate must not be null if (certificate == null) @@ -1399,7 +1400,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { PrivilegeContext privilegeContext = this.privilegeContextMap.get(certificate.getSessionId()); if (privilegeContext == null) { String msg = MessageFormat.format("There is no session information for {0}", certificate); //$NON-NLS-1$ - throw new AccessDeniedException(msg); + throw new NotAuthenticatedException(msg); } // validate certificate has not been tampered with @@ -1416,7 +1417,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { ZoneId.systemDefault()); if (dateTime.plusHours(1).isBefore(LocalDateTime.now())) { invalidateSession(sessionCertificate); - throw new PrivilegeException("Certificate has already expired!"); //$NON-NLS-1$ + throw new NotAuthenticatedException("Certificate has already expired!"); //$NON-NLS-1$ } } @@ -1433,7 +1434,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler { } @Override - public PrivilegeContext getPrivilegeContext(Certificate certificate) throws PrivilegeException { + public PrivilegeContext getPrivilegeContext(Certificate certificate) + throws PrivilegeException, NotAuthenticatedException { // first validate certificate isCertificateValid(certificate); diff --git a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PrivilegeHandler.java b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PrivilegeHandler.java index a3acc15ff..67cc906a4 100644 --- a/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PrivilegeHandler.java +++ b/li.strolch.privilege/src/main/java/li/strolch/privilege/handler/PrivilegeHandler.java @@ -20,6 +20,7 @@ import java.util.Locale; import java.util.Map; import li.strolch.privilege.base.AccessDeniedException; +import li.strolch.privilege.base.NotAuthenticatedException; import li.strolch.privilege.base.PrivilegeConflictResolution; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.model.Certificate; @@ -603,8 +604,10 @@ public interface PrivilegeHandler { * * @throws PrivilegeException * if there is anything wrong with this certificate + * @throws NotAuthenticatedException + * if the certificate has expired */ - public void isCertificateValid(Certificate certificate) throws PrivilegeException; + public void isCertificateValid(Certificate certificate) throws PrivilegeException, NotAuthenticatedException; /** * Returns the {@link PrivilegeContext} for the given {@link Certificate}. The {@link PrivilegeContext} is an @@ -617,8 +620,11 @@ public interface PrivilegeHandler { * * @throws PrivilegeException * if there is a configuration error or the {@link Certificate} is invalid + * @throws NotAuthenticatedException + * if the certificate has expired */ - public PrivilegeContext getPrivilegeContext(Certificate certificate) throws PrivilegeException; + public PrivilegeContext getPrivilegeContext(Certificate certificate) + throws PrivilegeException, NotAuthenticatedException; /** * Validate that the given password meets certain requirements. What these requirements are is a decision made by diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/DefaultStrolchSessionHandler.java b/li.strolch.rest/src/main/java/li/strolch/rest/DefaultStrolchSessionHandler.java index ba0a845a3..c06344c2b 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/DefaultStrolchSessionHandler.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/DefaultStrolchSessionHandler.java @@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory; import li.strolch.agent.api.ComponentContainer; import li.strolch.agent.api.StrolchComponent; -import li.strolch.exception.StrolchException; +import li.strolch.exception.StrolchNotAuthenticatedException; import li.strolch.privilege.base.AccessDeniedException; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.model.Certificate; @@ -152,22 +152,26 @@ public class DefaultStrolchSessionHandler extends StrolchComponent implements St } @Override - public Certificate validate(String authToken) { + public Certificate validate(String authToken) throws StrolchNotAuthenticatedException { DBC.PRE.assertNotEmpty("authToken must be set!", authToken); //$NON-NLS-1$ Certificate certificate = this.certificateMap.get(authToken); - if (certificate == null) - throw new StrolchException(MessageFormat.format("No certificate exists for sessionId {0}", authToken)); //$NON-NLS-1$ + throw new StrolchNotAuthenticatedException( + MessageFormat.format("No certificate exists for sessionId {0}", authToken)); //$NON-NLS-1$ return validate(certificate); } @Override - public Certificate validate(Certificate certificate) { - this.privilegeHandler.isCertificateValid(certificate); - certificate.setLastAccess(new Date()); - return certificate; + public Certificate validate(Certificate certificate) throws StrolchNotAuthenticatedException { + try { + this.privilegeHandler.isCertificateValid(certificate); + certificate.setLastAccess(new Date()); + return certificate; + } catch (PrivilegeException e) { + throw new StrolchNotAuthenticatedException(e.getMessage(), e); + } } @Override diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchSessionHandler.java b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchSessionHandler.java index 2678b7519..f84496bc4 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/StrolchSessionHandler.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/StrolchSessionHandler.java @@ -18,6 +18,7 @@ package li.strolch.rest; import java.util.List; import java.util.Locale; +import li.strolch.exception.StrolchNotAuthenticatedException; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.model.Certificate; import li.strolch.privilege.model.Usage; @@ -30,9 +31,9 @@ public interface StrolchSessionHandler { public Certificate authenticate(String username, char[] password); - public Certificate validate(String authToken); + public Certificate validate(String authToken) throws StrolchNotAuthenticatedException; - public Certificate validate(Certificate certificate); + public Certificate validate(Certificate certificate) throws StrolchNotAuthenticatedException; public void invalidate(Certificate certificate); diff --git a/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenticationRequestFilter.java b/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenticationRequestFilter.java index db2685946..bc8646ae5 100644 --- a/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenticationRequestFilter.java +++ b/li.strolch.rest/src/main/java/li/strolch/rest/filters/AuthenticationRequestFilter.java @@ -35,6 +35,8 @@ import javax.ws.rs.ext.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import li.strolch.exception.StrolchAccessDeniedException; +import li.strolch.exception.StrolchNotAuthenticatedException; import li.strolch.privilege.model.Certificate; import li.strolch.rest.RestfulStrolchComponent; import li.strolch.rest.StrolchRestfulConstants; @@ -46,7 +48,7 @@ import li.strolch.utils.helper.StringHelper; * @author Robert von Burg */ @Provider -@Priority(Priorities.AUTHENTICATION) +@Priority(Priorities.AUTHENTICATION) public class AuthenticationRequestFilter implements ContainerRequestFilter { private static final Logger logger = LoggerFactory.getLogger(AuthenticationRequestFilter.class); @@ -105,6 +107,15 @@ public class AuthenticationRequestFilter implements ContainerRequestFilter { .getComponent(StrolchSessionHandler.class); Certificate certificate = sessionHandler.validate(sessionId); requestContext.setProperty(STROLCH_CERTIFICATE, certificate); + } catch (StrolchNotAuthenticatedException e) { + logger.error(e.getMessage()); + requestContext.abortWith( + Response.status(Response.Status.UNAUTHORIZED).header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN) + .entity("User is not authenticated!").build()); //$NON-NLS-1$ + } catch (StrolchAccessDeniedException e) { + logger.error(e.getMessage()); + requestContext.abortWith(Response.status(Response.Status.FORBIDDEN) + .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN).entity("User is not authorized!").build()); //$NON-NLS-1$ } catch (Exception e) { logger.error(e.getMessage()); requestContext.abortWith(