Can Spring's caching framework be made aware of the authentication status of the request context, or is it easier to roll your own caching solution?
Regardless of the fact I find the use case super weird, you can condition caching for pretty much anything that works with SpEL. And since you can call any method you want with SpEL, you're good to go.
I realized that it is harder than it should but the following works. First create a static method that does your check (you can use the SecurityContextHolder for that)
public class SecurityChecker {
public static boolean isSecured() {
// Whatever
return SecurityContextHolder.getContext().getAuthentication() != null;
}
}
Then in your annotated method, specify the following (assuming myCache should be affected):
#Cacheable(cacheNames = "myCache", condition = "T(com.example.SecurityChecker).isSecured()")
public Foo doIt(String key) { ... }
There's two problems currently:
You can't create a meta-annotation to avoid repeating the condition attribute over and over again (see SPR-13475)
The SpEL setup does not allow you to easily call a method on a bean (which would be nicer than calling a static method). I've just created SPR-13812 for that
Related
In my spring project I have such an aspect class for logging
#Aspect
#Component
public class BaseLoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(BaseLoggingAspect.class);
#Target({ ElementType.FIELD, ElementType.PARAMETER })
public #interface NonLoggingField {
}
#Pointcut("execution(public * *(..))")
private void allPublicMethods() {
}
#Pointcut("within(img.imaginary.service.*)")
private void inServices() {
}
#Pointcut("within(img.imaginary.dao.*)")
private void inDao() {
}
#Before("allPublicMethods() && inServices() || inDao()")
public void logBeforeCall(JoinPoint joinPoint) {
if (logger.isDebugEnabled()) {
logger.debug("begin method {} in {} class with arguments: {}", joinPoint.getSignature().getName(),
joinPoint.getTarget().getClass().getSimpleName(), joinPoint.getArgs());
}
}
}
this aspect simply catches all the public methods of the service and dao layers and outputs to the log at the beginning of execution the name of the method, the name of the class, and the masi of the values of the arguments of the method
in this aspect, I created a NonLoggingField annotation that I want to apply to some fields of classes of those objects that can be passed to the parameters of these logged methods, for example this:
public class User {
#NonLoggingField
public String userEmail;
public name;
public User(String userEmail, String name) {
this.userEmail = userEmail;
this.name= name;
}
public String tiString() {
return String.format("user name: %s and his email: %s", name, userEmail);
}
}
the fact is that such objects will be written to the log through its toString method, but it is necessary that the email somehow does not get into the log using the notLoggingField annotation, while there are thoughts in my head to do through reflection, but there is no clarity how to do this without over difficult code using reflection, especially considering that objects may have objects of other types inside, which may have the same fields with annotations or collections with objects with such fields. perhaps the AspectJ library can help, but I can't find such mechanisms in it. Please help me come up with something
During runtime, a method parameter is just a value. The JVM does not know at this point if the caller called the method using constants, literals, fields or results of other method calls. That kind of information, you only see in the source code. In byte code, whatever dereferencing operation or computation necessary to determine the parameter's value (or a reference to the corresponding object) is done before calling the method. So there is no connection to the field annotation.
Would annotating method parameters be an alternative for you?
If your requirement is very specific, e.g. intercept field accesses from toString methods and return dummy values instead, if the field is annotated, that would be possible. But this would not be fool-proof. Imagine for example that toString calls a getter method instead of directly accessing the field or that a method other than toString logs the field. You do not always want to falisfy the field value on read access, because other parts of the application might rely on it working correctly. Not every toString call is made in order to log something.
I think you should solve the problem in another way, e.g. by applying filter rules for the logging tool you use. Or if you really want solve it at the application level, you could create an interface like
public interface PrivacyLogger {
String toStringSensitive();
}
and make each class containing sensitive information implement that interface. The logging aspect could then for each printed object determine if it is instanceof toStringSensitive(). If so, it would log the result of toStringSensitive() instead of toString(), i.e. in the simplest case something like
Object toBeLogged = whatever();
logger.log(
toBeLogged instanceof PrivacyLogger
? ((PrivacyLogger) toBeLogged).toStringSensitive()
: toBeLogged
);
Of course, you need to iterate over getArgs() and determine the correct log string for each object. Probably, you want to write a utility method doing that for the whole parameters array.
Moreover, in a complex class, the toStringSensitive() implementation should of course also check if its own fields are PrivacyLogger instances and in that case fold the values of their resapctive toStringSensitive() methods into itw own, so that it works recursively.
I am sorry I have no better news for you, but privacy is something which needs too be built into an application from the ground. There is no simple, fool-proof way to do that with one little aspect. The aspect can utilise the existing application infrastructure and avoid scattering and tangling, but it cannot decide on its own what needs to be prohibited from getting logged and what not.
Can you change a method's signature in Spring using aspects?
Like effectively transform the following:
#GetMapping("/thing")
#User // custom annotation that should authenticate the user
public ResponseEntity getThing() {
... // user is successfully authenticated, get the "thing" from the database
}
into:
#GetMapping("/thing")
public ResponseEntity getThing(#CookieValue("Session-Token") String sessionToken) {
User user = authenticator.authenticateSessionTokenOrThrow(sessionToken);
... // user is successfully authenticated, get the "thing" from the database
}
With the user variable also becoming available for use in the method body.
If not, how can I achieve the same result without repeating the code (parameter and authenticator call) everywhere?
Aspects aren't meant for that.
Yes, they can effectively modify .class files bytecode, with compile time or run time weaving, but they do not override methods' signatures.
Also, the default Spring AOP Aspects are implemented in pure Java, and thus cannot touch the bytecode layer. For that you'd need AspectJ.
Tools for customizing bytecode at run/compile time are ASM, ByteBuddy, CGLIB or Javassist.
However, you can probably accomplish this via an Annotation Processor, which lets you modify the actual sources, instead of the already compiled bytecode.
If not, how can I achieve the same result without repeating the code
(parameter and authenticator call) everywhere?
Possible solutions are
HandlerInterceptor, which simply throws an Exception if the user isn't authenticated
Standard Spring AOP advice, which simply throws an Exception if the user isn't authenticated
Spring Security
1 is pretty easy.
2 is more time-consuming
3 imho, seems the best match for authentication, but it's the most complex, probably
The HandlerInterceptor can choose which methods it applies to?
No, unfortunately. I had a requirement a couple of months ago to "cover" only certain methods with an Interceptor, and I implemented a custom solution, which simply look for an annotation specified on the method itself.
This is an extract of my custom HandlerInterceptor, which looks for the CheckInit annotation, first on the type, and then on the method, for a more specific customization.
#Override
public boolean preHandle(
final HttpServletRequest request,
final HttpServletResponse response,
final Object handler
) throws Exception {
if (handler instanceof HandlerMethod) {
if (shouldCheckInit((HandlerMethod) handler)) {
checkInit();
}
}
return true;
}
private static boolean shouldCheckInit(final HandlerMethod handlerMethod) {
final var typeAnnotation = handlerMethod.getBeanType().getAnnotation(CheckInit.class);
final var shouldCheckInit = typeAnnotation != null && typeAnnotation.value();
final var methodAnnotation = handlerMethod.getMethodAnnotation(CheckInit.class);
return (methodAnnotation == null || methodAnnotation.value()) && shouldCheckInit;
}
private void checkInit() throws Exception {
if (!manager.isActive()) {
throw new NotInitializedException();
}
}
The "Standard Spring AOP advice" seems interesting, do you have a link
for that?
Spring AOP documentation - look for the Java-based configuration (I hate XML)
AspectJ really touches the bytecode and can modify signatures as well?
You could make AspectJ modify signatures. Just fork the project and modify its Java Agent or compiler.
AFAIK Annotation Processors cannot modify classes, they can only
create new ones.
The thing is, they don't modify .class files, instead they modify source files, which means they simply edit them. E.g. Lombok uses annotation processing to modify source files.
But yes, the modified sources are written to a new file.
We created a resource, like:
#Path("whatever")
public class WhateverResource {
#POST
public Response createWhatever(CreateBean bean) { ...
#DELETE
#Path("/{uuid}")
public void deleteWhatever(#PathParam("uuid") UUID uuid) { ...
and so on for GET, PUT, HEAD.
Now we figured that we figured that we need to check whether the underlying feature is actually enabled. A single check, and when it fails, all operations should simply result in a 501.
My first thought was be to duplicate the existing resource, like:
#Path("whatever")
public class WhateverResourceIsntAvailable {
#POST
public Response createWhatever(CreateBean bean) {
throw 501
#DELETE
#Path("/{uuid}")
public void deleteWhatever(#PathParam("uuid") UUID uuid) {
throw 501
So, two resources, both specifying the exact same operations. Leading to the problem that we can't (easily) invoke that check at the point in time when the resource needs to be registered.
Beyond that, this duplication doesn't look very elegant, and I am wondering if there is a "more canonical" way of solving this?
EDIT: another option would be to add the check into the existing resource, into each resource, but that means: doing the check for each operation. Which can easily be forgotten when adding new operations.
I envision something like having:
a "base resource", that gets registered
when any operation is invoked on that resource, the request should be "delegated", depending on that underlying feature
either to a resource that just gives 501 always
or to the "real" resource that does the real work
And ideally, without duplicating checking code, or duplicating operation end point specs.
Following the suggestion given by user Samsotha, I implemented a simple filter, which is then "connected" via name binding, like:
#Path("whatever")
#MyNewFilter
public class WhateverResource {
...
And:
#MyNewFilter
public class MyNewFilterImpl implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext context) {
if (... feature is enabled )) {
... nothing to do
} else {
context.abortWith(
Response.status(Response.Status.NOT_IMPLEMENTED).entity("not implemented").build());
}
}
The major advantage of this approach is the fact that one can annotate individual operations, but also a whole resource, such as my WhateverResource. The latter will make sure that any operation within that resource is going through the filter!
( further details can be found in any decent Jersey tutorial, like the one at baeldung )
I have a class which takes a message with payload String.
The payload is then split and used to create an Entity which is passed to DAOInterface to persist.
How can you test the call daoInterface.insert(entity) has been made?
To Mock the DAOInterface and then verify the call to DAO requires the entity in the test class i.e.
verify(daoInterface).insert(entity);
Is this bad design i.e. creating the entity at this stage? Should the Sting[] split be passed to the DAOImplementaion and initialized there. Example problem,
public class ServiceClass {
#AutoWire
private DAOInterface daoInterface;
public void serviceMessage(Message<String> message) {
MessageHeaders mh = new MessageHeaders(message.getHeaders());
String[] split = ((String) mh.get("payload")).split("_");
code omitted
...
String type = mh.get("WhatType");
Entity entity = new Entity(split[0], split[1], split[2]);
if (type.equals("one"))
{
daoInterface.insert(entity); //How to test?
}
else
{
if (type.equals("two"))
{
doaInterface.modify(entity); //How to test?
}
}
}
}
You can verify with Mockito Matchers.
If you only care that the method is called with some Entity, you can verify that with
verify(daoInterface).insert(any(Entity.class));
If you care about which Entity, and the Entity class has an equals method, you can make an entity that should be equal to the one created and verify with
verify(daoInterface).insert(eq(expectedEntity);
If it's more complex than either of these cases, you can also write your own argument matchers.
The easiest thing you can do is injecting another collaborator to the service which will transform payload to Entity. This way you can keep control on object creation (Inversion of Control). Something like the example below injected to the ServiceClass should do the job:
interface PayloadTransformer {
public Entity transform(String payload);
}
This way your code will be easy to test and you split responsibilities which is usually a good thing. Have a look on Single Responsibility principle
Pushing transformation logic down to dao is almost never a good idea.
BTW. you can write else if without additional brackets and indentations. It's more readable like:
if (a) {
// do something
} else if (b) {
// do something
} else {
// do something
}
The last advice ServiceClass is really poor name for class. The word class is redundant here. Just name it Service, EntityService, MessageService or something which fits your case well.
I wouldn't name field with suffix *Interface as well. Underneath is some implementation injected, I assume. Better name it entityDao or just dao. It's up to you though :)
If you use a test framework like PowerMock, you can invoke private constructors and private methods in your test. This makes it easy to inject mock objects like a mock DAOInterface so you can retrieve it later and test it's been called.
For example, in PowerMock, to call a private constructor:
public class ServiceClass{
#Autowire
private final DAOInterface dao;
public ServiceClass() {
}
private ServiceClass(DAOInterface dao) {
this.dao = dao;
}
}
You simply do:
PrivateConstructorInstantiationDemo instance = WhiteBox.invokeConstructor(
PrivateConstructorInstantiationDemo.class,
new MockDAOInterface() );
So if you're using a dependency inject framework like above, this dovetails nicely. You don't normally have the dependency injection working during test, since it usually requires booting a large chunk of code with a lot of configuration.
By adding a single private constructor, you avoid breaking encapsulation, but you can still inject your mock object into the code during test with a test framework like PowerMock. This is considered best practice.
You could break encapsulation and add publicly accessible methods or ctors to the SeviceClass, but if you don't need them for your design it's not good practice to add them only for test. That's why people put such effort into bypassing encapsulation in frameworks like Mockito and PowerMock. It's not just a dodge around private code, it's because you want to keep the encapsulation while still being able to test.
EDIT:
If you're not familiar with making mock objects, you should do some Google searches on the subject. It's very common and a good skill to have. With the above code, you could make your own mock object. But making mocks is so common that most test frameworks will do this for you.
For example, in PowerMock, I just looked at their page on making mocks here. You can make a mock like this
DAOInteface myMock = createMock(DAOInterface.class);
You can then ask the mock to verify that methods are called:
expect(myMock.someMethod());
Now the mock 'expects' that method to be called, and if it isn't, it'll generate an error for your test. Pretty sweet actually.
You can also return values from a call:
expect(myMock.insert()).andReturn("Test succeeded");
so your code would then see the value "Test succeeded" when it called that method. I don't see that 'insert' does return a value, that's just an example.
Maybe I am just blind, but I do not see how to use Guice (just starting with it) to replace the new call in this method:
public boolean myMethod(String anInputValue) {
Processor proc = new ProcessorImpl(anInputValue);
return proc.isEnabled();
}
For testing there might be a different implementation of the Processor, so I'd like to avoid the new call and in the course of that get rid of the dependency on the implementation.
If my class could just remember an instance of Processor I could inject it via the constructor, but as the Processors are designed to be immutable I need a new one every time.
How would I go about and achieve that with Guice (2.0) ?
There is some time since I used Guice now, but I remember something called "assisted injection". It allows you to define a factory method where some parameters are supplied and some are injected. Instead of injecting the Processor you inject a processor factory, that has a factory method that takes the anInputValue parameter.
I point you to the javadoc of the FactoryProvider. I believe it should be usable for you.
You can get the effect you want by injecting a "Provider", which can by asked at runtime to give you a Processor. Providers provide a way to defer the construction of an object until requested.
They're covered in the Guice Docs here and here.
The provider will look something like
public class ProcessorProvider implements Provider<Processor> {
public Processor get() {
// construct and return a Processor
}
}
Since Providers are constructed and injected by Guice, they can themselves have bits injected.
Your code will look something like
#Inject
public MyClass(ProcessorProvider processorProvider) {
this.processorProvider = processorProvider;
}
public boolean myMethod(String anInputValue) {
return processorProvider.get().isEnabled(anInputValue);
}
Does your Processor need access to anInputValue for its entire lifecycle? If not, could the value be passed in for the method call you're using, something like:
#Inject
public MyClass(Processor processor) {
this.processor = processor;
}
public boolean myMethod(String anInputValue) {
return processor.isEnabled(anInputValue);
}