I like to add an user authentification to my REST webservice (Guice + Jersey).
I first wanted to solve the authentification with the Google Guice method interceptions. For example:
#Path("user")
public class User {
#OnlyAdmin
#Post
public void addUser(String apiKey) {
}
}
But unfortunately Guice only support AOP for classes with a no-argument constructors.
Is it generally a good idea to use AOP for user authentification?
Are there other frameworks to build an user authentification?
Edit: Framework is maybe the wrong term. I'm only looking for a way to inject some code in every annotated method and this code should check the parameters of the method
The only important point for AOP to work in your case is that your classes get created by Guice.
If you have constructors with arguments, ensure that they are injectable (directly or with assisted injection).
It wouldn't be AOP but you could inject a current user role bound to the request scope wherever the user needed to be checked and use either method intercepts or explicit logic to check that the right user class is performing some action.
Related
How can we force developer to write Developed Custom-annotation on rest api
Example :
We Developed annotation Called : ValidatePermission
what we need to do , displaying runtime error for developer that he missing annotation #ValidatePermission on API , when he tried to write new api
#ValidatePermission
#GetMapping("/details")
#PreAuthorize("hasAuthority('902')")
public ResponseEntity<CustDtlsInqDto> getCustomerDetails(#CurrentUser UserPrincipal currentUser,
#RequestParam(name = "poiNumber", required = false) String poiNumber,
#RequestParam(name = "cif", required = false) String cif) {
return ResponseEntity.ok(customerService.getCustomerDetailsByPoiOrCif(currentUser.getId(), poiNumber, cif));
}
Annotations usage cannot be forced in any way before or on compilation (at least I am not aware of any technique, feel free to correct me).
The only way to go is to perform a check-up during the unit testing phase. Simply write an unit test that scans through the REST API definition beans and its public methods (or annotated) to check up using teh Reflection API whether an annotation from a particular category (implementation details up to you) is present within the formal parameters of methods.
Gits Github: Find all annotated classes in a package using Spring
Baeldung: A Guide to the Reflections Library
Something looks to me weird in this approach.
So you say:
...displaying runtime error for developer that he missing annotation #ValidatePermission on API
Based on this phrase, let me suggest an alternative:
So the developer that runs the project locally (during the debugging session or maybe tests) should see an error if he/she didn't put the annotation on the methods of rest controller, right?
If so, Why don't you need the developers to put this annotation?
The main idea of my suggestion is: Why not letting spring to do it for you automatically?
You could implement some kind of aspect or if you don't want to use a spring aop and prefer 'raw plain spring', BeanPostProcessor, that would 'wrap' all the methods of class annotated with RestContoller (by creating a run-time proxy) and before running a controller method will executed the logic that was supposed to be supported by the annotation?
In the case of Web MVC, another approach is to implement an interceptor that will be invoked automatically by spring mvc engine and you'll be able to execute any custom logic you want there, you'll also be able to inject other beans (like auxiliary services) into the interceptor.
Read this article in case you're not familiar with these interceptors, you'll need preHandle methods as far as I understand.
Using Spring Security 5.2.X (latest currently), I need to prevent the access to a third party role to all methods but one in a SOAP service. In other words, I need that particular role to have access only to one particular method among all of the availables in the service.
Normally, a usual method level securization consists of annotation with #Secure("MY_ROLE"). This makes the method only to be accessible for that role.
Is it possible to tell Spring Security Core to do the opposite. I.e, configure it in a way that certain user only has access to the secured method.
Of course, the workaround could be:
// Method accessible by anyone but third party role
#Secured({"GOOD_ROLE1", "GOOD_ROLE2", "GOOD_ROLE3"})
public void methodAccessibleByAnyoneButThirdPartyRole(){
}
// Method accessible by anyone, including third party role
#Secured({"GOOD_ROLE1", "GOOD_ROLE2", "GOOD_ROLE3", "THIRD_PARTY_ROLE"})
public void methodAccessibleByAnyone(){
}
Other workaround would consist of just creating a new service only with the method to be restricted.
But is there any annotation option to get the same straightaway? Something like #PreAuthorize("!hasRole('THIRD_PARTY_ROLE')") or similar?
According to Spring Security doc you can use any Spring Expression Language (SpEL) in #PreAuthorize
Any Spring-EL functionality is available within the expression, so you
can also access properties on the arguments. For example, if you
wanted a particular method to only allow access to a user whose
username matched that of the contact, you could write
#PreAuthorize("#contact.name == authentication.name")
public void doSomething(Contact contact);
So you can use:
#PreAuthorize("!hasRole('THIRD_PARTY_ROLE')")
Also as more readable variant:
#PreAuthorize("not hasRole('THIRD_PARTY_ROLE')")
SUMMARY:
I have a self-contained class for performing a proxied login and then filling a HttpServletResponse object with authentication content a browser can use. When testing my code, how can I provide mocked services into a class that has no setters?
DETAILS:
I've severely edited my proxied login code into this snippet.
It asks the server for a login form.
It sends back the credentials.
It gets the server's approval and passes it to the browser
(response).
The trimmed code looks like this:
private static final Log log = LogFactory.getLog(MyClass.class);
#Inject()
private UserService userService;
public void performProxyLogin(HttpServletResponse response,
UserDTO userDTO, String url) {
String username = getUsername(userDTO);
String password = getPasswordFromUserService(username);
// MyRequest only has data, organizing a Http Request.
MyRequest myRequest = prepareInitialGetRequest(url);
// processURLRequest() encapsulates use of HttpURLConnection.
// MyResponse only has data, organizing a Http Response.
MyResponse myResponse = processURLRequest(myRequest);
myRequest = prepareLoginRequest(myResponse, username, password);
myResponse = processURLRequest(myRequest);
// Transfer data into the response, and from there into the browser.
fillResponseWithProxiedResult(response, myResponse)
}
To make this work I think I need to inject a mocked Log or LogFactory, a mocked UserService, and a way of getting a mocked HttpURLConnection.
However, all of the advice I've seen involves code with setters, which the test suite can use to plug in mocked objects.
How do I provide my class its needed mocked objects?
Bite the bullet and provide a package-private setter for this field.
If you want to use mocks, there's no value in letting the injection framework set up a mock which you can inject, since you're adding more ceremony and overhead to the set-up of your test.
If you want to validate that you have a service injecting correctly, you wouldn't want to use mocks at all (think "integration test" with real or pseudo-real components).
Many of the other answers hint at it, but I'm going to more explicitly say that yes, naive implementations of dependency injection can break encapsulation.
The key to avoiding this is that calling code should not directly instantiate the dependencies (if it doesn't care about them). This can be done in a number of ways.
The simplest is simply have a default constructor that does the injecting with default values. As long as calling code is only using the default constructor you can change the dependencies behind the scenes without affecting calling code.
This can start to get out of hand if your dependencies themselves have dependencies and so forth. At that point the Factory pattern could come into place (or you can use it from the get-go so that calling code is already using the factory). If you introduce the factory and don't want to break existing users of your code, you could always just call into the factory from your default constructor.
Beyond that there's using Inversion of Control. I haven't used IoC enough to speak too much about it, but there's plenty of questions here on it as well as articles online that explain it much better than I could.
If it should be truly encapsulated to where calling code cannot know about the dependencies then there's the option of either making the injecting (either the constructor with the dependency parameters or the setters) internal if the language supports it, or making them private and have your unit tests use something like Reflection if your language supports it. If you language supports neither then I suppose a possibility might be to have the class that calling code is instantiating a dummy class that just encapsulates the class the does the real work (I believe this is the Facade pattern, but I never remember the names correctly)]
I have a Spring MVC webpage that is used for password resets. This requires us to do the following validation workflow:
provide username OR email
if email is provided make sure it is valid format (ex: #Email)
Check that User exists by:
3a) Trying to load the user from the database via username
3b) if loading by username returns null, try to load the user from the database via email
After loading, check that user is not locked out: user.isLocked()
Currently I have all of these Validations inside a org.springframework.validation.Validator
However this requires my Validator to have access to the UserService object so it can load users. This causes the user to be loaded 2x, once by my validator and a second time by my Controller so it can invoke .resetPassword(User).
Question: Where should I be checking item #3 ?
Are those validations better suited for the Controller ? If I leave validation as is, can I return the User from the Validator (it has void method due to Validator interface)?
In my opinion, steps 3 and 4 don't belong to view layer (in particular, to validation performed by controller) at all.
These steps are essential parts of business logic for this scenario, therefore they should be implemented in service layer.
Your service layer should provide a method such as
public void resetPasswordByUsernameOrEmail(String usernameOrEmail) { ... }
and these steps should happen inside this method, along with resetPassword(User).
If you need, you can make controller aware of result of this method by throwing an exception, returning a boolean or an enum (if you want to distinguish between different error conditions).
To answer your questions in order:
You should do the checking for a User's existence in the UserDao.
No, these validations should not be in the Controller. The Controller shouldn't know anything about validation, otherwise it would be trying too do to much and we'd be guilty of low cohesion.
Since you're using an interface that defines a method with a void return, if you wanted to return a User you would have to do one of the following:
Create your own method in your Validator implementation. The disadvantage of this is that you could not use polymorphism as effectively since you would depend on a method not defined in the Interface.
Make your own Validator (possibly make your own Interface that extends Spring's Validator interface and defines the method you want). This is probably what I would choose.
Maybe that's a duplicate: Spring MVC Bean Validation
Another solution would be this:
In one of the projects I worked, we used to have a SpringBeanUtil class. It would get the WebApplicationContext, and get the bean needed through a static method.
It's kind of ugly, but helped on these kind of problems.
Use at you own risk.
public class SpringBeanUtil implements ApplicationContextAware{
private static ApplicationContext APPLICATION_CONTEXT;
#Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
APPLICATION_CONTEXT=applicationContext;
}
public static Object getBean(String name){
return APPLICATION_CONTEXT.getBean(name);
}
public static <T> T getBean(Class<T> type){
return APPLICATION_CONTEXT.getBean(type);
}
}
Consider some basic authorization framework with Users and Groups where access to methods should be guarded by checks which make sure that the user or the group have the necessary PriviledgeLevel to execute the method and fails otherwise.
What I imagine is something like this:
#AccessCheck(PriviledgeLevel.ADMINISTRATOR)
public static void secureMethod(){ ... }
Where the code checking basically does
if(currentUser.getPriviledgeLevel >= PriviledgeLevel.ADMINISTRATOR ||
currentUser.getGroup.priviledgeLevel >= PriviledgeLevel.ADMINISTRATOR)
// Allow access
else
// Deny access
Would it be possible to implement it this way?
I did a bit of research which points to some existing things based on AspectJ, mostly on the Security Annotation Framework (SAF) and on Spring Security.
I'm a bit concerned because SAF doesn't seem very active anymore and the documentation isn't that great.
I'm not sure about Spring Security but it seems to be more focused on security problems in web-related topics.
The Java Authentication and Authorization Service seems to be related, but doesn't use the annotation approach.
Does it make sense trying to define these security requirements with this declarative approach?
Is there another library/framework I'm missing, which already implements what I want or some techonology which would be relevant here?
Or is there a completely different solution (like implementing my own ClassLoader, ...) which is superior to what I imagine (in terms of conciseness and readability for the library user)?
I think AspectJ will do what you want it to do. We have a whole bunch of methods which you need certain access rights for and we've created an AspectJ aspect which will check that and error out if the user does not have those permissions.
As a plus, because AspectJ is "woven" into the classes at compile time it cannot be disabled by configuration.
We also use Spring Security, it is possible to use both in harmony!
You could do this fairly trivially yourself by using dynamic proxies.
public interface MyInterface {
#AccessCheck(Privilege.ADMIN)
public void doSomething();
}
The proxy would be created on the class that implements your interface and you would annotate your interface with your custom annotation.
MyInterface aInterface = (MyInterface) java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
.getClassLoader(), obj.getClass().getInterfaces(),
new YourProxy(new Implementation());
In the invoke() method of your proxy, you can check if your method has the annotation and throw a SecurityException if the privileges are not met.
public YourProxy implements InvocationHandler {
....
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ( method.isAnnotationPresent(AccessCheck.class) {
....// do access check here and throw SecurityException()
}
}
With Spring Security, you just have to add:
#Secured("ADMINISTRATOR")
public static void secureMethod(){ ... }
And configure it properly, by:
use JdbcDaoImpl as your UserDetailsService
enable group support
customize the queries (if you are using database credential storage)
If you are not using database credential storage, just configure your preferred UserDetailsService to add both user and group credentials to the authorities of the generated UserDetails.
Of couse, it is hard to understand it without checking the concepts at the documentation, but method level access checks is perfectly possible with spring security and it's my prefered technology for it.
In Spring Security, as the docs state, both #Secured and #PreAuthorize can be used at method level.
To enable #PreAuthorize (if you haven't already...), you need to put <global-method-security pre-post-annotations="enabled" />
in your configuration XML;
For #Secured use <global-method-security secured-annotations="enabled" />.
For more details, refer to this article.