SSouhaieb
SSouhaieb

Reputation: 238

Spring security allows any type of role (ROLE_USER/ROLE_ADMIN) to access to resources

I would like to integrate spring security with jsf and the problem I had is that spring security does not filter access to resources ie ROLE_USER can access to an xhtml that its access is defined "ROLE_ADMIN". My spring-security config file:

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- Enable method level Spring Security by annotations -->
    <sec:global-method-security pre-post-annotations="enabled" />

    <sec:http auto-config="true" use-expressions="true">
        <sec:intercept-url pattern="/javax.faces.resource/*" access="permitAll" />
        <sec:intercept-url pattern="/pages/login.xhtml" access="permitAll" />
        <sec:intercept-url pattern="/pages/index.xhtml" access="permitAll" />
        <sec:intercept-url pattern="/pages/admin/admin.xhtml" access="hasRole('ROLE_ADMIN')" />
        <sec:form-login login-page="/pages/login.xhtml"
            authentication-failure-url="/pages/login.xhtml?error=true"
            authentication-success-handler-ref="loginSuccessHandler" />
        <sec:logout logout-success-url="/pages/login.xhtml" />
    </sec:http>
    <bean id="serviceManager"
        class="com.souhaieb.education.cursus.security.SecurityManagerSupport" />

    <sec:authentication-manager alias="authenticationManager">
        <sec:authentication-provider user-service-ref="serviceManager">
            <sec:password-encoder hash="plaintext"></sec:password-encoder>
        </sec:authentication-provider>
    </sec:authentication-manager>
    <bean id="loginSuccessHandler"
        class="com.souhaieb.education.cursus.security.LoginSuccessHandler" />
</beans>

the login method in managedbean:

public String login() {
    try {
        Authentication request = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        Authentication result = authenticationManager.authenticate(request);
        SecurityContextHolder.getContext().setAuthentication(result);
    } catch (AuthenticationException e) {
        e.printStackTrace();
        return "pretty:error";
    }
    return "pretty:home"; // pages/index.xhtml
}

and here is the implementation of UserDetailsService

public class SecurityManagerSupport implements UserDetailsService {

@Autowired
private AuthenticationService authenticationService;

public UserDetails loadUserByUsername(final String userName)
        throws UsernameNotFoundException {
    com.souhaieb.education.cursus.ws.client.authentication.User user = authenticationService.getUserByUserName(userName);
    if(user == null){
        throw new UsernameNotFoundException(userName+ " not found");
    }
    /*PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    user.setPassword(passwordEncoder.encode(user.getPassword()));*/
    String username = user.getUserName();
    String password = user.getPassword();
    boolean enabled = user.isEnabled();
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;
    return new User(username, password, enabled, accountNonExpired,
                credentialsNonExpired, accountNonLocked, getAuthorities(user.getUserRoleList().getUserRoles()));

}
.
.
.

web.xml

    <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">

    <display-name>Cursus Management</display-name>

    <!-- <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param> -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext-security.xml
            /WEB-INF/applicationContext.xml
        </param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>server</param-value>
    </context-param>
    <context-param>
        <param-name>com.ocpsoft.pretty.DEVELOPMENT</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>primefaces.THEME</param-name>
        <param-value>bootstrap</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <listener>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

    <filter-mapping>
        <filter-name>Pretty Filter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>ERROR</dispatcher>
    </filter-mapping>

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>Pretty Filter</filter-name>
        <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
    </filter>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Upvotes: 0

Views: 1459

Answers (1)

SSouhaieb
SSouhaieb

Reputation: 238

The problem was the <sec:intercept-url pattern> of the pages. I should have used URLs instead of JSF view IDs. For example, /admin instead of /pages/admin/admin.xhtml. I was using PrettyFaces for friendly URLs and this got me confused.

<sec:http auto-config="true" use-expressions="true">
    <sec:intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" />
    <sec:intercept-url pattern="/login" access="permitAll" />
    <sec:intercept-url pattern="/home" access="permitAll" />
    <sec:form-login login-page="/login"
        authentication-success-handler-ref="loginSuccessHandler" />
    <sec:logout logout-success-url="/login" />
</sec:http>

Upvotes: 1

Related Questions