I have implemented spring security in controller method.
Below is my spring security.xml
-->
<!-- URL pattern based security -->
<security:http auto-config="false" entry-point-ref="authenticationEntryPoint"
use-expressions="true">
<custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url access="hasAnyRole('ROLE_ADMIN','ROLE_USER')" pattern="/common/admin/**" />
<security:intercept-url pattern="/common/accounting/**" access="hasRole('ROLE_USER')" />
<security:logout logout-url="/j_spring_security_logout" invalidate-session="true" logout-success-url="/login"/>
</security:http>
Below is my controller
#Secured({"ROLE_ADMIN"})
#RequestMapping(value = "/common/admin/addAdmin", method = RequestMethod.GET)
public String add(ModelMap map) {
map.addAttribute(new Administrator());
return "/common/admin/addAdmin";
}
#Secured({"ROLE_ADMIN"})
#RequestMapping(value = "/common/admin/addAdmin", method = RequestMethod.POST)
public String processadd(
#ModelAttribute("administrator") Administrator administrator) {
this.administratorManager.addAdmin(administrator);
return "/common/admin/success";
}
I allow the url /common/admin/** for both admin and user role. But i do some restriction in the admin controller. when user is go in to /common/admin/* as a user role, he can but he can also go in to method that is only for admin role only.
How can I solve it?
Thanks!
You already have added the #Secured annotation.
But you need to enable it:
<!-- secured-annotations = (#Secured("ROLE_ADMIN")) -->
<!-- jsr250-annotations = (#RunAs #RolesAllowed #PermitAll #DenyAll #DeclareRoles) -->
<!-- pre-post-annotations = #PreAuthorized("hasAuthority('ROLE_ADMIN')") -->
<global-method-security
secured-annotations="enabled"
jsr250-annotations="disabled"
pre-post-annotations="disabled">
</global-method-security>
#Secured can take a single or several roles.
#Secured("ROLE_USER")
#Secured({"ROLE_USER", "ROLE_ADMIN"}) //grand access if the user has one of this roles
BWT: From Spring Security 3 Book (http://www.springsecuritybook.com/):
The #Secured annotation is functionallz and syntactiallz the same as #RollesAllowed ... As #Secured functions the same as the JSR standard #RollesAllowed there's not reallz a compelling reason to use it (#Secured) in in new code...
(do not forgett to enable it jsr250-annotations="enabled")
I believe you could have multiple roles defined with #Secured annotation . Is this what you need?
If this is the case , try #RolesAllowed
Check this FAQ. Make sure the global-method-security element is in the web context file if you want to apply security to Spring MVC controllers.
Also, you may need to enable class proxying, using
<global-method-security secured-annotations="enabled" proxy-target-class="true" />
if your controller implements an interface and the method you are securing is not part of that interface (you'll also need cglib as an additional dependency in your app for this).
IF you want to use annotations, better put the following in servlet.xml. There is no point of enabling the annotations n spring-security-xml as it will not take any effect.
Putting above in servlet.xml will do the trick.
Related
I want to make an interceptor that will intercept every request except that related to login. The problem that I have is the interceptor still intercepts the requests that I provided with exclude-mapping. But the exclude-mapping is not working.
Here is the configuration,spring 4.3:
<mvc:interceptors>
<beans:bean class="com.knowledge.filter.GlobalInterceptor" />
<mvc:interceptor>
<mvc:mapping path="/back" />
<mvc:exclude-mapping path="/back/login" />
<beans:bean class="com.knowledge.filter.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
In my opinion, the "/back/login" should not be intercepted. Actually still get into the class of the interceptor.So, do i make some mistakes?
I recommend writing separate mapping for every individual path instead of grouping it until and unless you have common implementation for all the services. Excluding will be possible if login and back are separate rest controllers, Not one being child of other.
You can refer this example for spring 4.
http://www.kscodes.com/spring-mvc/spring-mvc-interceptor-example/
I am trying to implement Spring security authentication in my web application.
I found this in a book. The config in my security.xml:
<http ...>
…
<form-login login-page="/login/form"
login-processing-url="/login"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/login/form?error"/>
</http>
To make Spring MVC aware of the new URL this is put in WebMvcConfig.java:
import org.springframework.web.servlet.config.annotation.
ViewControllerRegistry;
...
public class WebMvcConfig extends WebMvcConfigurationSupport {
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/login/form")
.setViewName("login");
}
...
}
I was wondering how to implement this if I am using an xml app-config file, instead of the java config file. This is because I am using xml config mostly in my app.
Thanks.
It's in the Configuring View Controllers section of Spring docs
<mvc:view-controller path="/login/form" view-name="login"/>
I thinks I read the same book with you, but if I use WebMvcConfig.java to add the new URL I got 404 "login/form" is not available error. However, if I use the XML config, it work.
I'm using spring security 3.1.4 and I have the following problem:
I implemented my custom SavedRequestAwareAuthenticationSuccessHandler and I implemented a cache SessionRegistry.
The problem is that the session id that I get in the SessionRegistry.registerNewSession is different then the on i get in SavedRequestAwareAuthenticationSuccessHandler .onAuthenticationSuccess
The session registery is called first.
what is the correct one? How can I get the same in both?
Is there a way that the custom SessionRegistry.registerNewSession will take the spring security session id?
Just a mere guess. But it sounds like the following issue.
In Spring security by default there is a feature enabled called session fixation protection.
It migrates the session to a new ID for a security reason.
Imagine somebody supplies you an url with an existing session ID via email, you click the link and login.
Now the person who can supplied you the url, can simply hack your account by using the supplied session id.
If you want to disable it, you can do so by putting the following line in your spring security configuration. However be aware of the risk.
<http .. >
...
<session-management session-fixation-protection="none">
...
</http>
The way I solved it was with the below steps:
Added a new bean for SessionFixationProtectionStrategy
<bean id="sessionFixationProtectionStrategy" class="org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy" />
Added the new bean in # 1 as a property to the AuthenticationFilter bean
<bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
...
<property name="sessionAuthenticationStrategy" ref="sessionFixationProtectionStrategy" />
...
</bean>
Added a session management configuration with session-fixation-protection property in the <security:http> tag
<security:http>
<security:headers />
<security:csrf disabled="true"/>
...
<security:session-management session-fixation-protection="changeSessionId" />
</security:http>
Per Spring Security doco, SessionFixationProtectionStrategy is used as SessionAuthenticationStrategy for Java EE Servlet API implementations pre 3.1 - https://docs.spring.io/spring-security/site/docs/4.2.13.BUILD-SNAPSHOT/apidocs/org/springframework/security/web/authentication/session/SessionFixationProtectionStrategy.html, whilst from Servlet API 3.1, ChangeSessionIdAuthenticationStrategy should be used.
I am trying to develop a User management tool using Waffle to perform windows authentication with Spring Security. Unfortunately, The only thing that provides me is the authentication part.
I would like to assign a Role to a particular user session in order to limit a users privileges. Each username is stored in a database along with their associated role. How can I get Spring Security to query my database and load the associated role to the session, so that I can use the #PreAuthorize(hasRole(role)) annotation in my controller to restrict access to certain actions?
Edit:
Thanks for your answer but I don't think thats quite what I am looking for.
So I have made some progress(I think). For my Authentication provider I have created my own custom GrantedAuthorityFactory as a property of my waffleSpringAuthenticationProvider as follows:
<bean id="waffleSpringAuthenticationProvider" class="waffle.spring.WindowsAuthenticationProvider">
<property name="AllowGuestLogin" value="false" />
<property name="PrincipalFormat" value="fqn" />
<property name="RoleFormat" value="both" />
<property name="AuthProvider" ref="waffleWindowsAuthProvider" />
<property name="grantedAuthorityFactory" ref ="simpleGrantedAuthorityFactory"/>
<!-- -->
</bean>
The grantedAuthorityFactory code is as follows:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
import waffle.spring.GrantedAuthorityFactory;
import waffle.windows.auth.WindowsAccount;
public class SimpleGrantedAuthorityFactory implements GrantedAuthorityFactory{
private final String PREFIX;
private final boolean CONVERT_TO_UPPER_CASE;
#Autowired
#Qualifier(value = "jdbcRoleDao")
private JdbcRoleDao jdbcRoleDao;
public SimpleGrantedAuthorityFactory(String prefix, boolean convertToUpperCase)
{
PREFIX = prefix;
CONVERT_TO_UPPER_CASE = convertToUpperCase;
}
#Override
public GrantedAuthority createGrantedAuthority(WindowsAccount windowsAccount) {
System.out.println("Username: "+windowsAccount.getFqn());
String grantedAuthorityString = windowsAccount.getFqn();
String grantedAuthority = jdbcRoleDao.getRole(grantedAuthorityString);
return new SimpleGrantedAuthority(PREFIX+grantedAuthority);
}
}
Now when I run the program and try to log in, the login fails. When I remove my custom factory property from the config file, the login is completed successfully with no assigned roles. I'm not sure if this is important, but windowsAccount.getFqn() is not returning the correct username that I enter on my login form.
Is there something I'm missing from my factory class?
You have two options:
Configure JdbcDaoImpl as your UserDetailsService if you use provided DB schema
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="yourDataSource">
</authentication-provider>
</authentication-manager>
Write and configure your own UserDetailsService if you use custom DB schema.
<authentication-manager>
<authentication-provider user-service-ref="idOfYourCustomUserDetailsService" />
</authentication-manager>
I created a small and simple webapp using Spring Security and SpringMVC and I'm trying to convert it to be a multi-tenant application.
The concept I want is to re-use actual JSPs I have and alter their contents based on configuration which I determine based on the path of the URL.
Example:
Customer #1 (abc) - URL: http://mydomain.com/abc/login.html
Customer #2 (xyz) - URL: http://mydomain.com/xyz/login.html
So the name of the "tenant" is a prefix to the page's path.
I modified my controller to be like this:
#Controller
#RequestMapping("/{customer:[a-zA-Z0-9]+}/login.htm")
public class LoginController
{
private static final Logger logger = Logger.getLogger(LoginController.class);
#RequestMapping
#ReadOnlyRequest
public String login(#PathVariable("customer") String customer, HttpServletRequest request)
{
// Do some 'customer' related actions here
return "login"; // Map to the 'login.jsp' view
}
}
My view resolver configuration is:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
Until now, I had the following form-login configuration:
<form-login
login-page="/login.htm"
authentication-failure-url="/login.htm?error=true"
login-processing-url="/login_process"
default-target-url="/index.jsp"
always-use-default-target="true"
/>
But I do not know how to convert it to support my changes.
Is there a way to convert it to something like:
<form-login
login-page="/${customer}/login.htm"
authentication-failure-url="/${customer}/login.htm?error=true"
login-processing-url="/${customer}/login_process"
default-target-url="/index.jsp"
always-use-default-target="true"
/>
One possible idea is to use URL rewriting instead of manual handling of tenant identifiers. This way you can completely decouple tenant handling logic from your code, for example, as follows:
You define an inbound rewriting rule that converts /abc/login.html to /login.html and saves tenant identifier as a request attribute.
You define an outbound rule that appends the current tenant identifier to URLs being written into response. I think Spring Security should respect such a rule when sending redirects (if it doesn't, you can define a custom RedirectStrategy).
Though I have not tested this idea and cannot be sure that it would work.
See also:
OCPSoft Rewrite
UrlRewriteFilter