0

ZK + spring + spring security + java configuration

asked 2016-05-27 11:34:50 +0800

catzk gravatar image catzk
1

Hello,

I have a web application using spring and spring security with java configuration. This work with jsp page but not with zul. I have no error, only "Chargement..." is display, without waiting. What is wrong in the code below ?

web.xml (I must have to remove "http" to post my question)

<web-app xmlns="://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="://xmlns.jcp.org/xml/ns/javaee ://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">
<!-- Start ZK -->
<servlet>
    <description>ZK loader for evaluating ZUML pages</description>
    <servlet-name>zkLoader</servlet-name>
    <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
    <init-param>
        <param-name>update-uri</param-name>
        <param-value>/zkau</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zhtml</url-pattern>
</servlet-mapping>
<servlet>
    <description>The asynchronous update engine for ZK</description>
    <servlet-name>auEngine</servlet-name>
    <servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>auEngine</servlet-name>
    <url-pattern>/zkau/*</url-pattern>
</servlet-mapping>
<!-- End ZK -->

<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>

<session-config>
    <session-timeout>
        300
    </session-timeout>
</session-config>

</web-app>

HelloWordConfiguration.java

    package test.sfs.springsecurity.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "test.sfs")
@Import(value = SecurityConfiguration.class)
@Order(1)
public class HelloWorldConfiguration extends WebMvcConfigurerAdapter {

    @Bean(name="HelloWorld")
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
//      viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".zul");

        return viewResolver;
    }

    /*
     * Configure ResourceHandlers to serve static resources like CSS/ Javascript etc...
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }
}

SecurityConfiguration.java

    package test.sfs.springsecurity.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("USER");
        auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      http.authorizeRequests()
        .antMatchers("/admin/**").access("hasRole('ADMIN')")
        .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
                .anyRequest().authenticated()
        .and().formLogin().loginPage("/login").permitAll()
        .usernameParameter("ssoId").passwordParameter("password")
        .and().csrf()
        .and().exceptionHandling().accessDeniedPage("/Access_Denied");
    }
}

SecurityWebApplicationInitializer.java

    package test.sfs.springsecurity.configuration;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

}

SpringMvcInitializer.java

package test.sfs.springsecurity.configuration;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { HelloWorldConfiguration.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/", "*" };
    }

}

HelloWordController.java

package test.sfs.springsecurity.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HelloWorldController {


    @RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
    public String homePage(ModelMap model) {
        model.addAttribute("greeting", "Hi, Welcome to mysite");
        return "welcome";
    }

    @RequestMapping(value = "/admin", method = RequestMethod.GET)
    public String adminPage(ModelMap model) {
        model.addAttribute("user", getPrincipal());
        return "admin";
    }

    @RequestMapping(value = "/db", method = RequestMethod.GET)
    public String dbaPage(ModelMap model) {
        model.addAttribute("user", getPrincipal());
        return "dba";
    }

    @RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
    public String accessDeniedPage(ModelMap model) {
        model.addAttribute("user", getPrincipal());
        return "accessDenied";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String loginPage() {
        return "login";
    }

    @RequestMapping(value="/logout", method = RequestMethod.GET)
    public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null){    
            new SecurityContextLogoutHandler().logout(request, response, auth);
        }
        return "redirect:/login?logout";
    }

    private String getPrincipal(){
        String userName = null;
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        if (principal instanceof UserDetails) {
            userName = ((UserDetails)principal).getUsername();
        } else {
            userName = principal.toString();
        }
        return userName;
    }

}

pom.xml (I must have to remove "http" to post my question)

    <project xmlns="://maven.apache.org/POM/4.0.0" xmlns:xsi="://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="://maven.apache.org/POM/4.0.0 ://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>test-sfs</groupId>
    <artifactId>sfs-test</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>

    <name>sfs-test</name>

    <properties>
        <springframework.version>4.2.6.RELEASE</springframework.version>
        <springsecurity.version>4.1.0.RELEASE</springsecurity.version>

        <zk.version>8.0.0</zk.version>
        <zkspring.version>3.2.0</zkspring.version>
        <!--<zkspring.security.version>3.2.0</zkspring.security.version>-->
                <spring-release-train.version>Hopper-SR1</spring-release-train.version>
                <spring-data.version>1.10.1.RELEASE</spring-data.version>
                <hibernate.version>4.3.7.Final</hibernate.version>
        </properties>

    <dependencies>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springframework.version}</version>
        </dependency>

        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${springsecurity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${springsecurity.version}</version>
        </dependency>

                <dependency>
                    <groupId>org.springframework.data</groupId>
                    <artifactId>spring-data-jpa</artifactId>
                    <version>${spring-data.version}</version>
                </dependency>

            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-entitymanager</artifactId>
                <version>${hibernate.version}</version>
            </dependency>
            <!-- Start zk -->
            <dependency>
                <groupId>org.zkoss.zk</groupId>
                <artifactId>zkplus</artifactId>
                <version>${zk.version}</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-jdk14</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.zkoss.zk</groupId>
                <artifactId>zkbind</artifactId>
                <version>${zk.version}</version>
            </dependency>
            <dependency>
                <groupId>org.zkoss.zk</groupId>
                <artifactId>zkspring-core</artifactId>
                <version>${zkspring.version}</version>
            </dependency>
                        <!--
            <dependency>
                <groupId>org.zkoss.zk</groupId>
                <artifactId>zkspring-security</artifactId>
                <version>${zkspring.security.version}</version>
            </dependency>
                        -->
            <!-- End zk -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

        <dependencyManagement>
            <dependencies>
        <!-- Spring Data -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-releasetrain</artifactId>
            <version>${spring-release-train.version}</version>
                        <scope>import</scope>
                        <type>pom</type>
        </dependency>

            </dependencies>
        </dependencyManagement>

        <build>
            <finalName>${project.artifactId}</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.4</version>
                    <configuration>
                        <warSourceDirectory>src/main/webapp</warSourceDirectory>
                        <warName>${project.artifactId}</warName>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

With or without web.xml, the result is the same ...

If, in HelloWordConfiguration, I replace viewResolver.setSuffix(".zul"); by viewResolver.setSuffix(.jsp"); my login page is diplayed.

Thanks.

delete flag offensive retag edit

10 Answers

Sort by ยป oldest newest most voted
0

answered 2016-05-30 01:27:05 +0800

MDuchemin gravatar image MDuchemin
2560 1 6
ZK Team

Hi Catzk,

Do you get any error in your browser's java console when stuck on the "chargement" spinner? Try to look if the page is missing any resources. While the login page should be public with this configuration, it might be trying to load resources from a private location.

You may have to allow non-zul documents served through [your webapp]/zkau/ to guests, as the UI packages will be loaded from there.

If you get any Javascript error in your console, can you send it here too?

Regards, MDuchemin

link publish delete flag offensive edit
0

answered 2016-05-30 05:28:56 +0800

arcangelSalazar gravatar image arcangelSalazar
36 2

Check adding this to your configuration:

<sec:http use-expressions="true" auto-config="true">
    <sec:headers>
           <sec:frame-options policy="SAMEORIGIN"/>
            </sec:headers>
    <sec:csrf disabled="true"/>
    ...
</sec:http>
link publish delete flag offensive edit
0

answered 2016-05-31 08:06:45 +0800

catzk gravatar image catzk
1

Hello MDuchemin,

There is effectively error messages in console :

GET 
....://localhost:8081/sfs-test/login [HTTP/1.1 200 OK 21 ms]
SyntaxError: expected expression, got '<' zk.wpd:1:0
SyntaxError: expected expression, got '<' zul.lang.wpd:1:0
SyntaxError: expected expression, got '<' zkbind.wpd:1:0
GET 
....://localhost:8081/sfs-test/zkau/web/af058fa0/zul/css/zk.wcs [HTTP/1.1 302 Found 3 ms]
GET 
....://localhost:8081/sfs-test/login [HTTP/1.1 200 OK 10 ms]
ReferenceError: zk is not defined      login:16:1"

And if I try again :

ReferenceError: zkmx is not defined     login:16

For information, login.zul and login.jsp are in the same folder.

http:// (image description)

link publish delete flag offensive edit
0

answered 2016-05-31 08:17:17 +0800

catzk gravatar image catzk
1

For arcangelSalazar, I add .and().headers().frameOptions().sameOrigin(); in the SecurityConfiguration.java and comment .and().csrf() by I have always the same error ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {

      http.authorizeRequests()
//      .antMatchers("/", "/home").permitAll()
        .antMatchers("/admin/**").access("hasRole('ADMIN')")
        .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
                .anyRequest().authenticated()
        .and().formLogin().loginPage("/login").permitAll()
        .usernameParameter("userName").passwordParameter("password")
//      .and().csrf()
        .and().exceptionHandling().accessDeniedPage("/Access_Denied")
                  .and().headers().frameOptions().sameOrigin();
    }
link publish delete flag offensive edit
0

answered 2016-05-31 11:17:49 +0800

MDuchemin gravatar image MDuchemin
2560 1 6
ZK Team

Hi Catzk,

It looks like the packages call are receiving something else. If you look at the network tab and check the response for these packages, I would guess that they have been redirected to the authentication page instead. (in this case, instead of javascript, the reply would be the html document for the login page, or a redirect call to said page).

ZK requires these packages to render a zul page, and cannot function if the end user do not have access to them. (JSP pages do not require additional javascript resources unless you explicitly include them, which explain why the JSP login page can be rendered) All of these resources should be loaded from the /zkau/* path.

The simplest way to make these packages available to the end user would be to make the /zkau/ uri public by removing spring-security filtering on them. important note: if you create a custom package containing zul files and include this custom package in your classpath, some included zul pages may be served through this uri. In this case, a more robust solution would be to make all documents except ".zul" files public under /zkau/*.

link publish delete flag offensive edit
0

answered 2016-05-31 12:32:04 +0800

catzk gravatar image catzk
1

MDuchemin,

I add .antMatchers("/zkau/**").permitAll() and my login page is now diplay. BUT my stylesheet is not loaded and when I submit my login page, I have the error message

Request method 'POST' not supported

Here is my login page :

<?xml version="1.0" encoding="UTF-8"?>
<zk xmlns=".ttp://www.zkoss.org/2005/zul"
        xmlns:h="native"
    xmlns:xsi=".ttp://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation=".ttp://www.zkoss.org/2005/zul .ttp://www.zkoss.org/2005/zul/zul.xsd">
    <window border="none" width="100%" height="100%">
        <borderlayout height="100%">
            <center border="none" flex="true" autoscroll="true"
                sclass="main-body" style="padding: 5px">
                <box align="center" pack="center">
                    <h:form name="loginForm" action="login" method="POST">
                        <hlayout>
                            <div width="20px">
                            </div>                    
                            <label value="test login zul" sclass="banner-head" />
                        </hlayout>
                        <separator spacing="30px" />
                        <zk if="${param.error != null}">
                            <label value="${labels.login_failed} : ${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message}" style="color:red; font-size:1.5em;" />
                            <separator spacing="30px" />
                        </zk>
                        <h:table>
                            <h:tr>
                                <h:td>
                                    <label value="Utilisateur"/>
                                </h:td>
                                <h:td>
                                    <textbox name="username" focus="true" />
                                </h:td>
                            </h:tr>
                            <h:tr>
                                <h:td>
                                    <separator spacing="20px" />
                                </h:td>
                            </h:tr>
                            <h:tr>
                                <h:td>
                                    <label value="Mot de passe"/>
                                </h:td>
                                <h:td>
                                    <textbox type="password" name="password"/>
                                </h:td>
                            </h:tr>
                            <h:tr>
                                <h:td>
                                    <separator spacing="50px" />
                                </h:td>
                            </h:tr>
                            <h:tr>
                                <h:td colspan="2" align="center">
                                    <h:input type="submit" value="Submit"/>
                                </h:td>
                            </h:tr>
                        </h:table>
                    </h:form>
                </box>
            </center>
        </borderlayout>
    </window>
</zk>

An idea ?

link publish delete flag offensive edit
0

answered 2016-06-01 02:01:34 +0800

MDuchemin gravatar image MDuchemin
2560 1 6
ZK Team

Hi Catzk,

I see that your security declaration include:

@RequestMapping(value = "/login", method = RequestMethod.GET)

and your login form has a post method:

<h:form name="loginForm" action="login" method="POST">

I think that changing your form method to GET should help with this error.

You mentioned that your stylesheet isn't loaded, did you get any error in the dev tools? Any unresolved resources in the network tab? I would recommend trying to load the stylesheet directly in your browser. If you can just navigate to it, then there is probably an issue in the page link to the stylesheet. If you are redirected or denied, then you will need to fix that in order to display the retrieve the stylesheet when accessing the login page.

Regards, MDuchemin

link publish delete flag offensive edit
0

answered 2016-06-01 08:47:48 +0800

catzk gravatar image catzk
1

Hi MDuchemin,

I change POST to GET in my login.zul but it's the login.zul that is displayed again when I submit. I also try with "RequestMethod.POST" in my controller but nothing change. In the login.jsp, it's also a POST and that work !

For the stylesheet, it's OK. I add a "permitAll" on the folder that contains my css file.

Thanks.

link publish delete flag offensive edit
0

answered 2016-06-02 02:03:09 +0800

MDuchemin gravatar image MDuchemin
2560 1 6
ZK Team

Hi Catzk,

Not sure if it helps, but someone had a similar issue here: http://forum.zkoss.org/question/66693/zk-using-both-get-and-post-at-the-same-time/

It look like their issue was solved by using:

method = {RequestMethod.GET,RequestMethod.POST}

Does this have any effect on your problem?

Regards, MDuchemin

link publish delete flag offensive edit
0

answered 2016-06-02 08:32:32 +0800

catzk gravatar image catzk
1

Hi MDuchemin,

I had try that but that not work. However by adding http.csrf().disable(), I have now the message

Bad credential

There is progress ... ;-)

Thank for your help.

link publish delete flag offensive edit
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow
1 follower

RSS

Stats

Asked: 2016-05-27 11:34:50 +0800

Seen: 142 times

Last updated: Jun 02 '16

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More