I want to see if it is possible to use annotations to evaulate if a user is logged in or not.
Example
#AuthRequired
public String myProtectedArea() {
return View("view/protectedArea"); // If user is NOT authenticated, return "view/login"
}
As per your edit:
Check this SO Post:
Scanning Java annotations at runtime
I'd still recommend using Spring Security for this, it's tested and secure:
#PreAuthorize("hasRole('ROLE_USER')")
public String myProtectedArea() {
return View("view/protectedArea");
}
The annotation will check if the user is logged in and has the required credentials.
Another way with Spring Security is to intercept the URL pattern by setting this inside a spring.security-settings.xml:
<intercept-url pattern="/view/protectedArea/*" access="hasRole('ROLE_USER')" />
I'd recommend using both to maximize security.
In the security settings file you can then tell spring security where to redirect the user to login. If the user is already logged in, you can redirect him to yet another page:
<form-login login-page="/view/login.xhtml" default-target-url="/view/protectedArea/home.xhtml"
authentication-failure-url="/view/login.xhtml" />
It's a tested framework and thus secure and versatile. However it requires a bit of setting up if you want more than the standard behaviour.
The annotation doesn't check if the user is logged in or not--annotations are metadata on classes/methods. Something must still make use of the annotation.
Something in your code checks to see if the method is annotated with #AuthRequired, if it is, checks if logged in, then executes the method based on that.
For example, a web app might look for the annotation in a filter, base servlet, interceptor, etc. and decide whether or not the request process should continue.
Depending upon what type of application you are creating there are a number of options available to you for defining authentication levels for specific methods.
I would most likely recommend to you Spring Security for such a task.
Something like the below example would be the end result after configuration using Spring Security.
#Secured( {"USER_ROLE"} )
public String getSecretData() {
return "SECRET! SHHH!";
}
Then only users verified by Spring Security to have the role you provide to the annotation will have authorization to call the method.
There are a couple other annotation options in Spring Security you can utilize such as #PreAuthorize.
Instead of re-inventing the wheel, have a look at JAAS:
http://docs.oracle.com/javaee/6/tutorial/doc/bncbx.html#bncca
http://docs.oracle.com/javaee/6/tutorial/doc/bncas.html
http://docs.oracle.com/javaee/6/tutorial/doc/gijrp.html
http://docs.oracle.com/javaee/6/api/javax/annotation/security/package-summary.html
Related
We have a bunch of secured web services (using spring security) defined like this:
#GetMapping("/users/{userId}")
public User getUserInfo(#PathVariable String userId) {
...
#GetMapping("/users/{userId}/addresses")
public User getUserInfo(#PathVariable String userId) {
If I want to get the logged in user, I can add the Principal principal or HttpServletRequest request to the method and spring will support the data for the logged in user, or also I can use SecurityContextHolder.getContext().getAuthentication().
So far so good, if we want to get the logged in user for the api /users/1234 we have no problem. However we got a requirement to support a relative userId value being me where the api would be /users/me.
We could resolve this by adding in each api just an if statement and replacing the userId me with the real logged in userId. We don't like this implementation since we have a boilerplate code in 20 apis. So, another solution we tried was by just adding an aspect to replace the me by the real userId but I don't like using reflection for solving this problem.
So, i was wondering if there is a "spring boot" way of doing this? I haven't found any feature supporting this behavior.
I think the best solution would be to change that URL. If statement is ver explicit too though. There are interceptors as well you could use but I don't see them as being much different to using aspects, pretty evil stuff. But if you do use aspects I would suggest that you have an annotation such as #Me which you could annotated method inputs such as userId with, which would replace them with the id of the principal if the parameter is equal to me.
I'm using Spring Security to Secure my Web App.
I have a page where I show foo objects for administrators.
<intercept-url pattern="/show_foo/**" access="hasRole('ROLE_ADMIN')" />
But now I have a requirement that a foo cannot be seen by all the Administrators, for example only administrators with city="New York" can access to the element.
I've did something in my controller to solve this :
#RequestMapping(method=RequestMethod.GET,value="/show_foo"
public ModelAndView showfunction(Principal user)
{
User user2 = userService.getUserByName(user.getName());
if(/* some checks on user2 */)
/* show page */
else
/* show error page*/
}
So my question is : can I avoid the database call, because I need this almost in all of my pages and I find it ugly to check each time at the top of any controller the same thing over and over. Is there a Spring Security feature for this kind of use cases?.
With Expression based rules you can accesss principal even on rule. See: http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
For example if you can include needed information on principal object.
<intercept-url pattern="/show_foo/**" access="hasRole('ROLE_ADMIN') and principal.name=='xyzzy' " />
you have to put in some logic.
1.) Either load the user and country mapping and store somewhere in Static HashMap, remember to update the map if any changes done in mapping, can store same at session level.
2.) Load entries in 2nd level cache, or make queries cacheable, enable query caching as well.
You need to integrate Spring Security with Domain-ACLs. See a full explanation here.
Yo can consider mapping the relationship between Administrators and Cities using
ACL_OBJECT_IDENTITY instances.
I have implemented Spring Security Expression in my application Spring controller:
#Controller
#RequestMapping("init")
public class InitController {
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(value = "/", method = RequestMethod.GET)
public #ResponseBody String home(){
return "This is the init page";
}
}
With this security configuration:
<http auto-config="true" create-session="stateless" use-expressions="true">
<intercept-url pattern="/_ah*" access="permitAll" />
<intercept-url pattern="/init/*" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/init*" access="hasRole('ROLE_ADMIN')"/>
</http>
When this resource is accessed the the default Spring login form is displayed (http://localhost:8888/spring_security_login) however I don't want this to happen and that I just want to have the credentials to be inserted in the request header like "x-authorization-key" or whatever that fits the scenario.
What is the possible solution for this?
Is it a good to just have the x-authorization-key to be in the request
If so, how does it fit with the Spring security mechanism, that is how that it fit with the "hasRole" expression
It is important the the my web service is stateless, and each request gets authenticated
Finally, how to do deal with Spring security without having to deal with the Spring login form
header
You should probably read the description on what auto-config does, then remove it to disable form-login. Your configuration will be clearer if you specifically configure what you want to use.
It's not clear from your question what you want to be included in the x-authorization-key header. If you are just authenticating with a client Id and shared secret then you might as well use basic authentication since it is already supported out of the box and you can just add <http-basic /> to your configuration. If you have something more customized in mind, then you will probably have to implement a custom filter and add it to the Spring Security filter chain to extract the credentials and process them.
How your authentication mechanism fits is also dependent on what it actually consists of. Normally your users will have assigned roles which are loaded when they authenticate, usually from a database of some kind. The hasRole expression simply checks whether the current user has the specified role. Often you will only need to create a UserDetailsService which loads your user information in a standard format which is easily plugged into the framework. This is covered at length elsewhere. If you really need something more customized this blog article on GAE integration includes details of how you might go about integrating with a more complicated system.
Spring Security will not create or use a session if you use create-session='stateless'.
P.S. You don't really need to include the same security attributes both at the URL level and on your controller which handles the same URL.
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.