I'm trying to implement my #secured annotation similar to Spring's, but generalized to any project and I'm having problems.
I looked at a lot of documentation but my internet is really restringed and need an answer. My idea is that the code to use it is like this:
public class a {
#secured (access> 3)
private void a() {}
}
The controller:
public class SecuredProvider {
private void check () {
if (accessLevesOfMethod> registerUser.getAccesLevel ()) {
// execute method
} else {
throw new exception ();
}
}
in the main
new A (). a ();
And if the logged user have an access level < 3 throws an exception, any other case they method is executed normally.
Thanks in advance.
Solved with AOP, using Dependency injection with google's GUICE an intercepting every method with #Secure
Related
i am kind of stuck on a problem with creating beans, or probably i got the wrong intention.. Maybe you can help me solve it:
I got a application which takes in requests for batch processing. For every batch i need to create an own context depending on the parameters issued by the request.
I will try to simplyfy it with the following example:
I receive a request to process in a batch FunctionA which is a implementation for my Function_I interface and has sub-implementation FunctionA_DE and FunctionA_AT
Something like this:
public interface Function_I {
String doFunctionStuff()
}
public abstract class FunctionA implements Function_I {
FunctionConfig funcConfig;
public FunctionA(FunctionConfig funcConfig) {
this.funcConfig = funcConfig;
}
public String doFunctionStuff() {
// some code
String result = callSpecificFunctionStuff();
// more code
return result;
}
protected abstract String callSpecificFunctionStuff();
}
public class FunctionA_DE extends FunctionA {
public FunctionA_DE(FunctionConfig funcConf) {
super(funcConf)
}
protected String callSpecifiFunctionStuff() {
//do some specificStuff
return result;
}
}
public class FunctionA_AT extends FunctionA {
public FunctionA_AT(FunctionConfig funcConf) {
super(funcConf)
}
protected String callSpecifiFunctionStuff() {
//do some specificStuff
return result;
}
}
what would be the Spring-Boot-Way of creating a instance for FunctionA_DE to get it as Function_I for the calling part of the application, and what should it look like when i add FunctionB with FunctionB_DE / FunctionB_AT to my classes..
I thought it could be something like:
PSEUDO CODE
#Configuration
public class FunctionFactory {
#Bean(SCOPE=SCOPE_PROTOTYPE) // i need a new instance everytime i call it
public Function_I createFunctionA(FunctionConfiguration funcConfig) {
// create Function depending on the funcConfig so either FunctionA_DE or FunctionA_AT
}
}
and i would call it by Autowiring the FunctionFactory into my calling class and use it with
someSpringFactory.createFunction(functionConfiguration);
but i cant figure it out to create a Prototype-Bean for the function with passing a parameter.. And i cant really find a solution to my question by browsing through SO, but maybe i just got the wrong search terms.. Or my approach to solve this issue i totally wrong (maybe stupid), nobody would solve it the spring-boot-way but stick to Factories.
Appreciate your help!
You could use Springs's application context. Create a bean for each of the interfaces but annotate it with a specific profile e.g. "Function-A-AT". Now when you have to invoke it, you can simply set the application context of spring accordingly and the right bean should be used by Spring.
Hello everyone and thanks for reading my question.
after a discussion with a friend who is well versed in the spring framework i came to the conclusion that my approach or my favoured solution was not what i was searching for and is not how spring should be used. Because the Function_I-Instance depends on the for the specific batch loaded configuration it is not recommended to manage all these instances as #Beans.
In the end i decided to not manage the instances for my Function_I with spring. but instead i build a Controller / Factory which is a #Controller-Class and let this class build the instance i need with the passed parameters for decision making on runtime.
This is how it looks (Pseudo-Code)
#Controller
public class FunctionController {
SomeSpringManagedClass ssmc;
public FunctionController(#Autowired SomeSpringManagedClass ssmc) {
this.ssmc = ssmc;
}
public Function_I createFunction(FunctionConfiguration funcConf) {
boolean funcA, cntryDE;
// code to decide the function
if(funcA && cntryDE) {
return new FunctionA_DE(funcConf);
} else if(funB && cntryDE) {
return new FunctionB_DE(funcConf);
} // maybe more else if...
}
}
Below is my code snippet:
ServiceImpl.java
#Service
public class ServiceImpl implements Service {
private Response worker(Audit send) throws ArgumentException {
System.out.println("STEP_1");
worker(send.getRequest(), send.getId());
}
private Response worker(Request request, String id) throws ArgumentException {
System.out.println("STEP_2");
try {
//throwing some exception
} catch (Exception e) {
System.out.println("STEP_3");
}
}
}
Now, what I want is whenever NullPointerException is being thrown from method worker(Request request, String id) as shown above I want to perform some specific task. For that I have written an Aspect class which is following:
MyAspect.java
#Aspect
#Component
public class MyAspect{
#Pointcut("com.xyz.myapp.ServiceImpl.worker() && args(request,..)")
private void someOperation(Request request) {}
#Before("someOperation(request)")
public void process(Request request) {
System.out.println("SUCCESS");
}
#AfterThrowing("com.xyz.myapp.ServiceImpl.worker() && args(request,..)")
public void doRecoveryActions() {
System.out.println("EXCEPTION_SUCCESS");
}
}
Current Output:
STEP_1
STEP_2
STEP_3
Desired Output:
STEP_1
STEP_2
STEP_3
SUCCESS
EXCEPTION_SUCCESS
As you can see MyAspect.java is not getting triggered hence NOT printing values.
What can be the reason for this?
Note:
I tried making worker as public classes too but it didn't work.
Also tried changing the name of the methods to eliminate any overloading issue that too didn't work.
Tried various other pointcut expressions all in vain as of now.
In my application there are other aspect classes working absolutely fine.
You made a typical Spring AOP beginner's mistake: You assume that it works for private methods, but as the documentation clearly says, it does not. Spring AOP is based on dynamic proxies, and those only work for public methods when implementing interfaces via JDK proxies and additionally for protected and package-scoped methods when using CGLIB proxies.
You should make the worker() method public if you want to intercept it from an aspect.
P.S.: Full-fledged AspectJ also works for private methods, but to switch to another AOP framework would be overkill here.
Update: You also have other problems in your code:
The first worker method, even if you make it public, does not return anything. The last statement should be return worker(send.getRequest(), send.getId());, not just worker(send.getRequest(), send.getId());.
Your pointcut com.xyz.myapp.ServiceImpl.worker() will never match because it has an empty argument list, but your method has arguments. The args() does not help you here.
The syntax of your pointcut is also wrong because it does not specify a return type for the method, not even *. Furthermore, the method name itself is not enough, it should be enclosed in an actual pointcut type such as execution(). I.e. you want to write something like:
#Pointcut("execution(* com.xyz.myapp.ServiceImpl.worker(..)) && args(request, ..)")
private void someOperation(Request request) {}
To intercept a method that throws an exception you can use this code (works only if methods are public):
#AfterThrowing(pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",throwing="ex")
public void doRecoveryActions(NullPointerException ex) {
// ...
}
Source: Spring AOP
I develop web-app, with a need to store heavy-weight files and use Apache FTP Server for this purpose. When a new user register his account, the folder named as his username must be created on remote server. To establish connection, before UserCreatingServiceImpl.createUser() method will be performed, I use Spring AOP:
#Component
#Aspect
public class RemoteServerConnectionEstablisher {
private static boolean connectionEstablished = false;
#Autowired
private RemoteServerConnector serverConnector;
#Pointcut("execution(* com.storehouse.business.services.impl.UserCreatingServiceImpl.createUser(..)) ||"
+ " execution (* com.storehouse.business.services.impl.ItemCreatingServiceImpl.createItem(..)) ||"
+ "execution (* com.storehouse.business.services.impl.FileDownloadingServiceImpl.downloadFile(..))")
public void pointcut() {
}
#Before("pointcut()")
public void establishConnection(JoinPoint jp) {
if (!connectionEstablished) {
if (serverConnector.connectToRemoteServer()) {
connectionEstablished = true;
}
}
}
#After("pointcut()")
public void disconnect(JoinPoint jp) {
if (connectionEstablished) {
if (serverConnector.disconnect()) {
connectionEstablished = false;
}
}
}
}
Here is the service class with createUser() method:
#Service
public class UserCreatingServiceImpl implements UserCreatingService {
#Autowired
private UserService userService;
#Autowired
private FTPClient ftpClient;
#Override
public boolean createUser(UserDto userDto) {
try {
ftpClient.makeDirectory(userDto.getUsername());
UserMapper userMapper = new UserMapper();
userService.persistUser(userMapper.dtoToEntity(userDto));
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
#Transactional
public void checkIfUsernameExist(String username) {
}
}
Everything had worked fine, until I added #Transactional method to service -class:
#Transactional
public void checkIfUsernameExist(String username) {
}
Now methods of Aspect-class don`t invoke. Could you explain the reason. Thanks in advance for help.
The issue lies in your pointcut expression.
execution(* com.storehouse.business.services.impl.UserCreatingServiceImpl.createUser(..))
You are intercepting the execution of the createUser method on the UserCreatingServiceImpl. This works when you don't add something that creates a proxy for your implementation. As you will be directly calling this method.
However as you have added #Transactional a proxy is created and the method call is now done on the UserCreatingService as that is the interface that is left due do the created proxy. By default spring uses JDK Dynamic proxies, which are interface based.
To solve do one of these things
Rewrite your pointcut to operate on the interface instead of implementing class
Use class based instead of interface based proxies
Use compile or load time weaving
Rewrite pointcut
Use execution(* com.storehouse.business.services.UserCreatingService+.createUser(..)) instead of what you have now. This will use the interface instead of the concrete class.
Use class based proxies
Assuming you use #EnableAspectJAutoProxy add proxyTargetClass=true to it, leading to #EnableAspectJAutoProxy(proxyTargetClass=true). This will create class based proxies and should make the original pointcut work.
Use compile or load time weaving
Instead of using proxies you also could change the way your code is build/loaded. For compile time weaving you would have to modify your build to use the AspectJ compiler to apply the aspects at compilation time, then you don't need the proxies any more.
Or instead of #EnableAspectJAutoProxy you could add #EnableLoadTimeWeaving which, if you use a recent servlet container, would weave the aspects as soon as a class is being loaded.
Both would eliminate the need for proxies (at least for this part) and would make the original pointcuts work.
I'm a little new to AOP, and got confused about the problem I'm facing. I have the Annotation #AuthorizeUser which acts on methods, on Presentation Layer. I need to check if User is authorized to execute that method or not. Here is the code for AuthorizeUserAspect:
#Aspect
public class AuthorizeUserAspect {
#AuthoWired
private UserService service;
#Before(value = "#annotation(com.company.annotation.AuthorizeUser)")
public void isAuthorized(JoinPoint jp) {
// Check if the user has permission or not
// executing some Service Layer services and
// Persistence Layer, corresponding to that
service.checkUser();
// Is there a way I can make this method Conditional. something like:
if ( /* User has permission */ ) {
// do nothing, so the method will be executed after this
}
else {
// 1) Prevent the Method to be executed [and/or]
// 2) Pass some Parameters to the method for checking [and/or]
// 3) Execute another method on that class [e.g showAccessDenied()]
}
}
}
It's a little bit similar to this question Spring MVC + Before Advice check security. But it suggested to return some String (ie. "Not OK"). There are two types of UI in my application (Struts and Jersey), so there would be two type of return type (String and Response respectively). So I guess that might not be the best way to do it.
I would be very glad if you could show me a workaround for this.
Is this even a good approach or not?
First of all, have you looked at Spring Security? It is completely declarative and does not require you to write aspects yourself. It secures methods by throwing an exception if the user is not authenticated or doesn't have the required privilege.
Regarding your problem with two different return types:
First option: Create two different kinds of advices, specific to the return type of the method:
#Before("#annotation(com.company.annotation.AuthorizeUser) && execution(String *.*(..))")
public void isAuthorizedString(JoinPoint jp) {
...
}
#Before("#annotation(com.company.annotation.AuthorizeUser) && execution(Response *.*(..))")
public void isAuthorizedResponse(JoinPoint jp) {
...
}
Second option: Find out the return type of the advised method via reflection and return a different value based on that:
#Before("#annotation(com.company.annotation.AuthorizeUser")
public void isAuthorized(JoinPoint jp) {
Class<?> returnType = ((MethodSignature)jp.getStaticPart()
.getSignature()).getReturnType();
if(returnType == String.class)
...
else
...
}
I'd like to set up my beans to use both Hibernate Validator (for validation) and Google Guice (for DI and method interception).
Ideally, I'd like to have a setup where any method that "fails" validation will cause a method interceptor to be called:
public class Widget {
#NotNull
public Fizz getFizz() {
return fizz;
}
}
public class FailedWidgetInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// This gets executed if Widget's getFizz() returns null...
}
}
But it looks like Hibernate Validator only allows you to determine pass/fail status by explicitly passing an object T to a ClassValidator<T>'s getInvalidValues() method.
So I need a place to make such a call! The only viable solution I can think of is to create my own annotation (which I've never done before!) which might look like this:
#NotNull
public #interface AutoValidatingNotNull {
// ...??
}
And then in Guice Module:
public class WidgetModule implements Module {
public void configure(Binder binder) {
binder.bindInterceptor(
any(),
annotatedWith(AutoValidatingNotNull.class),
new ValidatingWidgetInterceptor()
);
}
}
public class ValidatingWidgetInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
ClassValidator<Widget> widgetValidator = new ClassValidator<Widget>();
InvalidValue[] badVals = widgetValidator.getInvalidValues(widget);
if(badVals.length > 0)
handleFailedValidationAndThrowRuntimeExceptionOrSomething();
}
}
Finally, to change getFizz():
#AutoValidatingNotNull
public Fizz getFizz() {
return fizz;
}
For one, this only almost works: inside the interceptor's invoke method, how do I get my hands on the widget instance (the one we wish to validate)?. Is there a way to pass the widget instance via annotations?
Edit:
Doesn't look like I can pass Object into annotations (as parameters)...
Second, this is kind of nasty. Perhaps I'm overlooking something that Hibernate Validator offers that takes care of all this for me? Is there a better way to go? Thanks in advance!
It seems like you're still using the Hibernate Validator 3.x API around ClassValidator et al.
I recommend to upgrade to 4.2 where an API for method validation was introduced which exactly does what you describe.
An example for the required glue code to integrate that API with Google Guice can be found in this project which I created a while ago on GitHub.