[New] Added new StrolchAccessDeniedException for use in ServiceHandler

Now if you add the DefaultServiceHandler property 'throwOnPrivilegeFail'
and set it to true, then the service handler will throw a
StrolchAccessDeniedException which in combination with the
StrolchRestfulExceptionMapper allows rest services to quickly determine
if the error was because the user does not have access to the requested
resource.

Same goes for performing queries in AbstractTransaction only there
instead of throwing a privilege exception, we now also throw a
StrolchAccessDeniedException
This commit is contained in:
Robert von Burg 2015-01-18 18:37:04 +01:00
parent 2de2e32c44
commit 9505ab355c
5 changed files with 146 additions and 17 deletions

View File

@ -32,6 +32,7 @@ import li.strolch.agent.impl.AuditingAuditMapFacade;
import li.strolch.agent.impl.AuditingOrderMap;
import li.strolch.agent.impl.AuditingResourceMap;
import li.strolch.agent.impl.InternalStrolchRealm;
import li.strolch.exception.StrolchAccessDeniedException;
import li.strolch.exception.StrolchException;
import li.strolch.model.GroupedParameterizedElement;
import li.strolch.model.Locator;
@ -65,6 +66,7 @@ import li.strolch.service.api.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.utils.dbc.DBC;
@ -237,8 +239,12 @@ public abstract class AbstractTransaction implements StrolchTransaction {
}
private void assertQueryAllowed(StrolchQuery query) {
PrivilegeContext privilegeContext = this.privilegeHandler.getPrivilegeContext(this.certificate);
privilegeContext.validateAction(query);
try {
PrivilegeContext privilegeContext = this.privilegeHandler.getPrivilegeContext(this.certificate);
privilegeContext.validateAction(query);
} catch (PrivilegeException e) {
throw new StrolchAccessDeniedException(this.certificate, query, e.getMessage(), e);
}
}
@Override

View File

@ -19,6 +19,7 @@ import java.text.MessageFormat;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchComponent;
import li.strolch.exception.StrolchAccessDeniedException;
import li.strolch.exception.StrolchException;
import li.strolch.runtime.configuration.ComponentConfiguration;
import li.strolch.runtime.configuration.RuntimeConfiguration;
@ -33,8 +34,10 @@ import ch.eitchnet.utils.helper.StringHelper;
*/
public class DefaultServiceHandler extends StrolchComponent implements ServiceHandler {
private static final String PARAM_THROW_ON_PRIVILEGE_FAIL = "throwOnPrivilegeFail";
private RuntimeConfiguration runtimeConfiguration;
private PrivilegeHandler privilegeHandler;
private boolean throwOnPrivilegeFail;
/**
* @param container
@ -48,6 +51,7 @@ public class DefaultServiceHandler extends StrolchComponent implements ServiceHa
public void initialize(ComponentConfiguration configuration) {
this.privilegeHandler = getContainer().getPrivilegeHandler();
this.runtimeConfiguration = configuration.getRuntimeConfiguration();
this.throwOnPrivilegeFail = configuration.getBoolean(PARAM_THROW_ON_PRIVILEGE_FAIL, Boolean.FALSE);
super.initialize(configuration);
}
@ -84,7 +88,7 @@ public class DefaultServiceHandler extends StrolchComponent implements ServiceHa
StringHelper.formatNanoDuration(end - start), e.getMessage());
logger.error(msg, e);
if (service instanceof AbstractService) {
if (!this.throwOnPrivilegeFail && service instanceof AbstractService) {
AbstractService<?, ?> abstractService = (AbstractService<?, ?>) service;
@SuppressWarnings("unchecked")
U arg = (U) abstractService.getResultInstance();
@ -93,7 +97,7 @@ public class DefaultServiceHandler extends StrolchComponent implements ServiceHa
arg.setThrowable(e);
return arg;
} else {
throw new StrolchException(e.getMessage());
throw new StrolchAccessDeniedException(certificate, service, e.getMessage(), e);
}
}
@ -113,16 +117,7 @@ public class DefaultServiceHandler extends StrolchComponent implements ServiceHa
}
// log the result
long end = System.nanoTime();
String msg = "User {0}: Service {1} took {2}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, username, service.getClass().getName(),
StringHelper.formatNanoDuration(end - start));
if (serviceResult.getState() == ServiceResultState.SUCCESS)
logger.info(msg);
else if (serviceResult.getState() == ServiceResultState.WARNING)
logger.warn(msg);
else if (serviceResult.getState() == ServiceResultState.FAILED)
logger.error(msg);
logResult(service, start, username, serviceResult);
return serviceResult;
@ -135,4 +130,42 @@ public class DefaultServiceHandler extends StrolchComponent implements ServiceHa
throw new StrolchException(msg, e);
}
}
private void logResult(Service<?, ?> service, long start, String username, ServiceResult serviceResult) {
long end = System.nanoTime();
String msg = "User {0}: Service {1} took {2}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, username, service.getClass().getName(),
StringHelper.formatNanoDuration(end - start));
if (serviceResult.getState() == ServiceResultState.SUCCESS) {
logger.info(msg);
} else if (serviceResult.getState() == ServiceResultState.WARNING) {
msg = ServiceResultState.WARNING + " " + msg;
logger.warn(msg);
if (StringHelper.isNotEmpty(serviceResult.getMessage()) && serviceResult.getThrowable() != null) {
logger.warn("Reason: " + serviceResult.getMessage(), serviceResult.getThrowable());
} else if (StringHelper.isNotEmpty(serviceResult.getMessage())) {
logger.warn("Reason: " + serviceResult.getMessage());
} else if (serviceResult.getThrowable() != null) {
logger.warn("Reason: " + serviceResult.getThrowable().getMessage(), serviceResult.getThrowable());
}
} else if (serviceResult.getState() == ServiceResultState.FAILED) {
msg = ServiceResultState.FAILED + " " + msg;
logger.error(msg);
if (StringHelper.isNotEmpty(serviceResult.getMessage()) && serviceResult.getThrowable() != null) {
logger.error("Reason: " + serviceResult.getMessage(), serviceResult.getThrowable());
} else if (StringHelper.isNotEmpty(serviceResult.getMessage())) {
logger.error("Reason: " + serviceResult.getMessage());
} else if (serviceResult.getThrowable() != null) {
logger.error("Reason: " + serviceResult.getThrowable().getMessage(), serviceResult.getThrowable());
}
}
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.privilege.model.Restrictable;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class StrolchAccessDeniedException extends StrolchException {
private static final long serialVersionUID = 1L;
private Certificate certificate;
private Restrictable restrictable;
/**
*
* @param certificate
* @param restrictable
* @param message
* @param cause
*/
public StrolchAccessDeniedException(Certificate certificate, Restrictable restrictable, String message,
Throwable cause) {
super(message, cause);
this.certificate = certificate;
this.restrictable = restrictable;
}
/**
*
* @param certificate
* @param restrictable
* @param message
*/
public StrolchAccessDeniedException(Certificate certificate, Restrictable restrictable, String message) {
super(message);
this.certificate = certificate;
this.restrictable = restrictable;
}
public Certificate getCertificate() {
return certificate;
}
public Restrictable getRestrictable() {
return restrictable;
}
}

View File

@ -227,8 +227,8 @@ public abstract class AbstractParameter<T> extends AbstractStrolchElement implem
*/
protected void validateValue(T value) throws StrolchException {
if (value == null) {
String msg = "{0} Parameter {1} may not have a null value!"; //$NON-NLS-1$
msg = MessageFormat.format(msg, getType(), getId());
String msg = "Can not set null value on Parameter {0}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, getLocator());
throw new StrolchException(msg);
}
}

View File

@ -4,12 +4,16 @@ import java.text.MessageFormat;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import li.strolch.exception.StrolchAccessDeniedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.utils.helper.StringHelper;
@Provider
@ -19,7 +23,29 @@ public class StrolchRestfulExceptionMapper implements ExceptionMapper<Exception>
@Override
public Response toResponse(Exception ex) {
logger.error(MessageFormat.format("Handling exception {0}", ex.getClass()), ex); //$NON-NLS-1$
return Response.status(500).entity(StringHelper.formatExceptionMessage(ex)).type(MediaType.TEXT_PLAIN).build();
if (ex instanceof StrolchAccessDeniedException) {
StrolchAccessDeniedException e = (StrolchAccessDeniedException) ex;
StringBuilder sb = new StringBuilder();
sb.append("User ");
sb.append(e.getCertificate().getUsername());
sb.append(" does not have access to ");
Restrictable restrictable = e.getRestrictable();
if (restrictable == null) {
sb.append(StringHelper.NULL);
} else {
sb.append(restrictable.getPrivilegeName());
sb.append(" - ");
sb.append(restrictable.getPrivilegeValue());
}
return Response.status(Status.FORBIDDEN).entity(sb.toString()).type(MediaType.TEXT_PLAIN).build();
}
String exceptionMessage = StringHelper.formatExceptionMessage(ex);
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(exceptionMessage).type(MediaType.TEXT_PLAIN)
.build();
}
}