How to securing my Java page programatically using Spring
#Secured({"ROLE_USER", "ROLE_ADMIN"})
public class SecretClass extends BasePage {
// do work
}
But I want to do it programatically, get role from db first and put it.
public class SecretClass extends BasePage {
// Something like:
// String role = userManager.getRole();
// #Secured({"ROLE_USER", role})
#InjectService("UserManager")
private UserManager userManager;
}
But, I know you can't do like that with #Secured, so is there any way to do what I want by code? For securing whole page, not particular method.
read about spring security it will give u the required features which you want for your application more secured. https://projects.spring.io/spring-security/
I would prefer using the framework and not implementing (and testing) your own code especially in security context.
But if you really need to implement your own logic, you should take a look at #PreAuthorize . #Secured is an old annotation and kind of deprecated since #PreAuthorize can do much more and uses the spring expression language.
In our Project we used #PreAuthorize(hasPermission(...)) and implemented our own logic within hasPermission(). But this might be an overkill for you, since #PreAuthorize can already do a lot!
Take a look at the documentation.
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.
I have a Spring web application which uses Spring SAML and Spring Security to manage the login process.
Now I need to do some tasks after the correct login occurs. In particular I have to store some data in the SecurityContext.getContext() object.
I have never worked with Spring Security/SAML and I don't know how it manages the return from the IdP.
Is there any place in the code where usually you can put your code after the login process ends correctly?
I mean, I know where the redirect page is set but I cannot put my custom code in the Controller of this redirect page because that page is accessed more than one time, and I need to run my custom code only once at login time.
The best approach is to implement interface SAMLUserDetailsService, which will automatically store object you return from its loadUserBySAML method in the Authentication object which you can later query from the SecurityContext.getContext(). The interface is called once after each authentication. See the manual for details and examples.
The other possibility is AuthenticationSuccessHandler. The login process calls method onAuthenticationSuccess which has access to the Authentication object, which will be stored in the SecurityContext.getContext().
Simply create your own class which implements interface AuthenticationSuccessHandler (you can also extend some of the existing classes, such as SimpleUrlAuthenticationSuccessHandler or AbstractAuthenticationTargetUrlRequestHandler). Then plug your implementation to the securityContext.xml by changing class in the existing successRedirectHandler bean.
The problem is, that the Authentication object tends to be immutable - so the first way might be better.
You can use AuthenticationSuccessEvent. Just register a bean that implements ApplicationListener.
#Component
public class SomeSpringBean implements
ApplicationListener<AuthenticationSuccessEvent> {
public onApplicationEvent(AuthenticationSuccessEvent event) {
String userName = ((UserDetails) event.getAuthentication().
//do stuff
}
}
And you need to register AuthenticationEventPublisher.
Take a look here: https://gist.github.com/msarhan/10834401
If you use custom authentication provider, you can also plug whatever you want there.
Are you using Spring's Java configs?
If so, then you probably have a class that overrides WebSecurityConfigurerAdapter in your project. Extending this class gives you access to override the method configure(HttpSecurity http).
You can use that provided HttpSecurity builder object to configure a lot of things, one of which is the authentication success handler. More or less, you can create a simple that class that implements AuthenticationSuccessHandler (Spring has a few classes already built for extension to make this easy), and you can call http.successHandler(yourSuccessHandler) to register it with Spring Security.
Implementing that interface gives you the hook to put custom code into the onAuthenticationSuccess( ... ) method. I think they have one for failures as well.
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.
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.
Does Spring Security provide any way to authorize a user in java class, the way it provides tags for authorization in JSPs (such as <sec:authorize ifAllGranted="ROLE_ADMIN"/>)?
I am expecting a static method of some class that I can use in my code like this:
if(SomeSpringSecurityClass.authorize("ROLE_ADMIN")){
...
}
You'd better do this check declaratively, but if you still need programmatic way - it has already been discussed on stackoverflow earlier: How to check "hasRole" in Java Code with Spring Security?
In short words, there's no such single ready-made method but you can start from SecurityContextHolder.getContext() to perform this check.