Method #Secured supposed to throw error when no user authenticated - spring

The code for my service follows...
#Controller
#GwtRpcEndPoint
public class ServerServiceImpl implements ServerService {
#org.springframework.security.annotation.Secured("ROLE_ADMIN")
public String runGwtSprMvcHibJpaDemo(String s) {
System.out.println("SecurityContextHolder.getContext()="+SecurityContextHolder.getContext());
System.out.println("SecurityContextHolder.getContext().getAuthentication()="+SecurityContextHolder.getContext().getAuthentication());
}
}
my applicationContext.xml
<security:global-method-security secured-annotations="enabled" jsr250-annotations="disabled" />
but when i call the serviceImpl through gwt-rpc, aren't runGwtSprMvcHibJpaDemo supposed to print out security error since user not yet authenticated? Rather, the method runGwtSprMvcHibJpaDemo is executed with output
SecurityContextHolder.getContext()=org.springframework.security.context.SecurityContextImpl#ffffffff: Null authentication SecurityContextHolder.getContext().getAuthentication()=null

Add
<security:http auto-config="true">
<security:intercept-url pattern="/**" access="ROLE_ADMIN" />
</security:http>
to your xml config and see if that fixes it.

Define bean in your spring context like:
bean id="userDetailsService"
class="packagename.MyUserService">.
Please note that bean name should be extactly same. Spring use this bean internally to start this service.
MyUserService is a implementation of UserDetailsService.

Related

Securing url pattern based on user properties Spring security

I have secured certain url patterns for my project based on the users role as seen in my spring_security xml below.
<security:http auto-config="true" use-expressions="true" access-denied-page="/auth/denied.do" >
<security:intercept-url pattern="/auth/login" access="permitAll"/>
<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>
<security:intercept-url pattern="/security/**" access="hasRole('ROLE_SECURITY')"/>
<security:intercept-url pattern="/common/**" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/notsecure/**" access="permitAll"/>
<security:form-login
login-page="/auth/login.do"
authentication-failure-url="/auth/login.do?error=true"
default-target-url="/common/tasks/tasks.do"
authentication-success-handler-ref="mySuccessHandler"/>
<security:logout
invalidate-session="true"
logout-success-url="/auth/login.do"
logout-url="/auth/logout.do"/>
</security:http>
<sec:global-method-security pre-post-annotations="enabled" />
<!-- Declare an authentication-manager to use a custom userDetailsService -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="authenticationService">
<!-- <security:password-encoder ref="passwordEncoder"/> -->
</security:authentication-provider>
</security:authentication-manager>
<!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
<!--
<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
-->
<!-- A custom service where Spring will retrieve users and their corresponding access levels -->
<bean id="authenticationService" class="ie.premiumpower.services.AuthenticationService"/>
<bean id="mySuccessHandler" class="ie.premiumpower.services.MySuccessHandler">
</bean>
So only admin users can access /admin/** etc.
Now I want to limit users to their own url pattern based on a different attribute (their site_id which is just an int). So only users with a site_id of 1 can go to the url "/1/**" and so on.
How can I go about doing this? Just looking for a point in the right direction. Everything I've seen so far doesn't allow me to have a variable url-pattern. As in "/{variable}/".
https://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
See "15.3 Method Security Expressions"
You can use something like
#PreAuthorize("#value == '123'")
#RequestMapping(value="/secure")
#ResponseBody
public String aloa(#RequestParam("value") String value, Principal principal) {
return "Hello " + principal.getName();
}
This will only let you in if you provide "value=123" as a request Parameter.
You may also use #PathVariable here:
#PreAuthorize("#value == '123'")
#RequestMapping(value="/secure/{value}/data")
#ResponseBody
public String aloa(#PathVariable("value") String value, Principal principal)
If you want fine-grain access control to your domain objects, you may want to use spring-acl for such purpose. There you can define fine grained access control for any object base on user permissions. Heres the simple base on which acl is base uppon, too. you can throw in your own implementation of PermissionEvaluator and then make use of "hasPermission" inside the #PreAuthorize:
Link it in in your security config:
<global-method-security secured-annotations="disabled" pre-post-annotations="enabled">
<expression-handler ref="expressionHandler"/>
</global-method-security>
<beans:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="myPermissionEvaluator"/>
</beans:bean>
create a "hasPermission" PreAuthorize constraint:
#PreAuthorize("hasPermission(#value, 'admin')")
#RequestMapping(value="/secure/{value}/data")
#ResponseBody
public String aloa(#PathVariable("value") String value, Principal principal)
Fill a PermissionEvaluator with life. Here you can bridge your domain-permission over to spring-security: The referenced value from your #RequestMapping will come in through the "targetDomainObject" in "permission" you'll find the required permission as defined in your "hasPermission" definition above.
#Component("myPermissionEvaluator")
public class MyPermissionEvaluator implements PermissionEvaluator {
#Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
return ...;
}
#Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
Object permission) {
return ...;
}
}
you may even directly access the Principal object from within the annotations, too:
#PreAuthorize("#value == authentication.principal.title") //my pricipal is from ldap source and title is mapped in from there.

Spring MVC, Method level security

I am trying to restrict access to my controller, based on user role. Now i can do that using the security.xml file in a following way
<http use-expressions="true">
<intercept-url pattern="/**" access="hasRole([ROLE_ADMIN,ROLE_USER])" />
</http>
But I dont want to do it this way. Rather i will write
<http use-expressions="true">
<intercept-url pattern="/**" access="isAuthenticated()"/>
</http>
and in the controller
#RequestMapping("/test")
#PreAuthorize("hasRole('ROLE_USER')")
public String test() {
return "test";
}
#RequestMapping("/testadmin")
#PreAuthorize("hasRole('ROLE_ADMIN')")
public String testAdminPage() {
return "testadmin";
}
now ROLE_USER can access both (ROLE_ADMIN & ROLE_ USER) tagged controller. this is the problem.
and based on this testadmin.jsp can only be viewed by ROLE_ADMIN type user and test.jsp can only be viewed by "ROLE_USER" type user.
To sum up rather than writing the access code in the xml file i want to control it from the controller.
How do i do this??
you have to enable method level security via
<global-method-security pre-post-annotations="enabled"/>
then your spring controllers are going to get proxied and the PreAuthorize annotation is going to be evaluated.
further information can be found here (section 16.3):
http://docs.spring.io/spring-security/site/docs/current/reference/el-access.html
EDIT:
I guess your Controller beans are being created in the Disptacher Servlet (the web-context) and your security configuration is in the root-context -> Controllers will stay unaffected by the BeanPostProcessor so you have to put the <global-method-security>tag in the web context config (dispatcher-servlet.xml?)

JSF2 with SpringSecurity: handle AccessDeniedException of #Secured-Annotation

i am using Spring-Security 3.1.3 with Spring 3.2.2 and Majorra 2.1.25. I don't use managed beans, but use SpringBeanFacesELResolver. So basically, i use spring for everything.
I use the following
<http auto-config="true">
<form-login login-page="/components/public/login.jsf" authentication-failure-handler-ref="customAuthenticationFailureHandler" />
<intercept-url pattern="/components/admin/**" access="ROLE_ADMIN" />
<intercept-url pattern="/components/secured/**" access="ROLE_USER,ROLE_ADMIN" />
<intercept-url pattern="/**" />
<session-management>
<concurrency-control max-sessions="1" expired-url="/components/public/sessionExpired.jsf" />
</session-management>
<access-denied-handler ref="customAccessDeniedHandler" />
</http>
which works as indended, e.g. on accessing a secured page, the user is directed to the login and after the login he is brought to the requested page. If he tries to reach an admin-page, but only has ROLE_USER, he is directed to the access-denied page by my customAccessDeniedHandler
So far so good. The problem now is the following:
i use #Secured({ "ROLE_ADMIN" }) on a method. If a user with insufficient rights accesses this method, an AccessDeniedException is thrown, which is just what i want. BUT: My customAccessDeniedHandler is not invoked! Why is that?
Some more info: The method is invoked as part of an AJAX call and i would like to use my handler to set a FacesMessage as Feedback. How do i do this centrally? I am pretty sure i could wrap another method around this and use try-catch to catch the AccessDeniedException myself. But doing this for every method that has to be secured will just bloat up my code with a massive amount of unnecessary try-catch-methods. How can i handle the Exception centrally?
I found a solution now. I use Spring-AOP and "bind" an around aspect to all methods annotated with #Secured
<!-- aspect configuration -->
<aop:config>
<aop:aspect id="securedAspect" ref="securityFeedbackAspect">
<aop:around pointcut="#annotation(org.springframework.security.access.annotation.Secured)" method="handleSecuredAnnotations" />
</aop:aspect>
</aop:config>
The aspect looks like this
#Service
public class SecurityFeedbackAspect {
public Object handleSecuredAnnotations(final ProceedingJoinPoint pjp) throws Throwable {
try {
return pjp.proceed();
} catch (AccessDeniedException e) {
// log + set feedback for user here
}
}
}
Hope this helps anyone someday. One addition info: Somehow i couldn't get this to work with annotation-only configuration, because the #Secured-check would always be invoked first and my aspect would only run if no exception was thrown by the Spring-Security-Logic. I ended up using XML configuration, which seems to always go first, since i found no other way (even with #Order)

Spring Security : How to access a protected service from the init method of a context bean?

My setup :
In a Spring MVC 3.1 application, I have a Spring Security protected service :
#PreAuthorize("isAnonymous()") // ("hasRole('USER')") doesn't work either
public interface UserService extends UserDetailsService, PasswordEncoder
I'm trying to use this service from the init() method of a bean declared in my context :
<bean class="com.xxx.scripts.FillDbWithInitialValues" init-method="contextInit" />
The class :
public class FillDbWithInitialValues
{
#Autowired
UserService userService;
public void contextInit()
{
User test = userService.getUser(1);
}
}
Extract of my security.xml file :
<sec:global-method-security pre-post-annotations="enabled" />
<sec:http auto-config="true" use-expressions="true">
(...)
</sec:http>
<sec:authentication-manager alias="authManager">
<sec:authentication-provider user-service-ref="userService">
<sec:password-encoder ref="userService" />
</sec:authentication-provider>
</sec:authentication-manager>
The problem :
When I start the application, I get an exception :
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
Why is this happening?
How can my bean be "authenticated" so it can use the service?
If there's no user authenticated there's no way of checking his roles. If you want that bean to be authenticated before calling the method i think you could try something in this way:
SecurityContextHolder.getContext().setAuthentication(new user here);
User test = userService.getUser(1);

Spring Security hasRole('ROLE_ADMIN') in config and #PreAuthorize("permitAll") not working?

I'm trying to lock down my entire app except a particular URL/method.
Here's my applicationContext-security.xml:
<global-method-security pre-post-annotations="enabled"/>
<http use-expressions="true">
<http-basic/>
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
<logout logout-success-url="/products" />
</http>
Here's the class with its annotation:
#RooWebScaffold(path = "products", formBackingObject = Product.class)
#RequestMapping("/products")
#Controller
public class ProductController {
#RequestMapping(value="/json", headers = "Accept=application/json")
#ResponseBody
#PreAuthorize("permitAll")
public String listJson() {
return Product.toJsonArray(Product.findAllProducts());
}
}
However, it's not working as expected.
If I swap the conditions around and have permitAll in the config and the hasRole() in the annotation it works as expected - but I'm trying to achieve the reverse.
Any advice would be greatly appreciated!
If you are using XML Configuration don't forget to add the following attribute:
<s:global-method-security pre-post-annotations="enabled"/>
If you are using Java Configuration don't forget to add the following annotation:
#EnableGlobalMethodSecurity(prePostEnabled = true)
It is almost similar to question spring security 3 - Setting up a customized login, if you restrict all access (pattern /**) to role_admin then how the permitAll on /product would work? Solution would be to provide IS_AUTHENTICATED_ANONYMOUSLY access on /product.
From #PreAuthorize and intercept-url priority
:
<intercept-url> ... takes precedence over (#PreAuthorize) annotations. [, since] <intercept-url> works at URL level and annotations at method level.
So the solution to your problem (apart from #PreAuthorize annotations) must be addressed in your security config.
You have to declare /prodcuts/json intercept url with permitAll (or anonymous..) before /** intercept url pattern like:
...
<intercept-url pattern="/products/json" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')" />
...
From https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#nsa-intercept-url:
When matching the specified patterns against an incoming request, the matching is done in the order in which the elements are declared. So the most specific patterns should come first and the most general should come last.

Resources