Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    SmartGWT 5.1 Authentication with Spring Security 4.2



    Hi everybody. I want to share my approach to authentication using Spring Security 4.2, getting the user credentials from HSQLDB, and with localized messages in the login page, in case someone can benefit from it. It will seem like a very long post, but if you compare to other methods described here and here, you'll see that the amount of coding you need to do to get it working is not that much, and it allows for basic authentication for simpler use cases, presenting a localized login page with some basic messages in case of wrong login information, and even a simple message when you log out.

    Note: I don't include relogin nor CSRF protection, because in my case those two things are no required (at least, not in the short-mid future).

    1. Create two tables in your HSQLDB engine:
    Code:
    CREATE TABLE IF NOT EXISTS users (
         username VARCHAR(50) NOT NULL,  
         password VARCHAR(50) NOT NULL,
         mode VARCHAR(50) NOT NULL,
         language VARCHAR(50) NOT NULL,
         enabled BOOLEAN NOT NULL,
         CONSTRAINT users_pk PRIMARY KEY (username)  
    )
    
    CREATE TABLE IF NOT EXISTS authorities (  
         username VARCHAR(50) NOT NULL,  
         authority VARCHAR(50) NOT NULL,  
         FOREIGN KEY (username) REFERENCES users(username)
    )
    2. Add some data to the tables:
    Code:
    insert into users(username,password,mode,language,enabled) values ('user','abc','basic','es',TRUE)
    insert into authorities(username,AUTHORITY) values ('user', 'ROLE_USER')
    3. Add the applicationContext.xml file in war/WEB-INF/. This file has almost everything required to make Spring Secuity 4.2 work in your app. Make it have the following contents:
    Code:
    <beans:beans xmlns="http://www.springframework.org/schema/security"
        xmlns:beans="http://www.springframework.org/schema/beans"
        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-3.0.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security.xsd">
            
        <!-- Basic security configuration -->
        <http auto-config="true" use-expressions="true">
            
            <!-- Security exceptions to allow proper login page resource loading -->
            <intercept-url pattern="/resources/**" access="permitAll"/>
            <intercept-url pattern="/login.jsp*" access="permitAll"/>
            
            <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
            <form-login 
                login-page="/login.jsp" 
                default-target-url="/myApp.html"
                always-use-default-target="true"
                authentication-failure-url="/login.jsp?error" 
                username-parameter="username"
                password-parameter="password" />
            <logout logout-url="/logout" logout-success-url="/login.jsp?logout"  />
            <!-- disable csrf protection -->
            <csrf disabled="true"/>
        </http>
        
        <!-- Specify the dataSource used for validating user login information with HSQLDB -->
        <beans:bean id="dataSource" 
            class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <beans:property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
            <beans:property name="url" value="jdbc:hsqldb:hsql://localhost/myApp" />
            <beans:property name="username" value="sa" />
            <beans:property name="password" value="" />
        </beans:bean>
        
        <!-- Define the queries required to validate users stored in HSQLDB's DB -->
        <authentication-manager>
            <authentication-provider>
                <jdbc-user-service data-source-ref="dataSource"
                      users-by-username-query="select username,password, enabled from users where username=?"
                      authorities-by-username-query="select username, authority from authorities where username =?  " />
            </authentication-provider>
        </authentication-manager>
            
        <!-- OPTIONAL: Specify the resources to be used for login page localization -->
        <beans:bean id="messageSource"
            class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
            <!-- MyAppRerources is the 'base name' for all my .properties files which contain the translated texts in the login page -->
            <beans:property name="basename" value="classpath:/co/myCompany/myApp/shared/i18n/MyAppResources" />
            <beans:property name="defaultEncoding" value="UTF-8" />
        </beans:bean>
            
    </beans:beans>
    4. Add these lines to web.xml, at the beginning of the file (this file should be also under war/WEB-INF/ if you started your app from one of the samples provided by Isomorphic):
    Code:
          <!-- Default page to serve: note that this isn't your default html page anymore... -->
          <!-- That page is going to be the one you go to after you authenticate, and it's configured above in -->
          <!-- applicationContext.xml using default-target-url="/myApp.html" -->
          <welcome-file-list>
            <welcome-file>login.jsp</welcome-file>
          </welcome-file-list>
      
          <!-- Servlets -->
    
          <listener> 
            <listener-class>org.springframework.web.context.ContextLoaderListener</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>
        </filter-mapping>
    5. Create your login.jsp page, and put it under your war/ folder. Please note that I don't include login.css here, because that file contains very specific information to our app and brand, but you can add your own css file that goes well with your own brand. Isomorphic's wiki has a good example of this that you can easily adapt. You will need to provide styling elements for all the css classes referenced in the login form, or you can just delete every class reference (class="somevalue").
    Code:
    ​<%@page isELIgnored ="false" %>
    <%@page contentType="text/html;charset=UTF-8" %>
    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
    
    <html>
    <head>
        <title>My App</title>
        <link href="<%= request.getContextPath() %>/resources/css/login.css" rel="stylesheet" type="text/css" />
    </head>
    <body class="login t_center" onload="document.f.username.focus();">
        <div class="content-login clearfix">
            <div class="content-display clearfix">
                <div class="log-in clearfix;">
                    <img class="logo-login" src="<%= request.getContextPath() %>/resources/images/login_logo.png" alt="App Logo" />
                    <div class="top-log-in">
                    </div>
                    <div class="body-log-in clearfix">
                        <h2 class="header-login"><spring:message code="login"/></h2>
                            
                        <form name="f" action="/login" method="POST">
                            <label><spring:message code="userName"/></label>
                            <input id="username" type="text" name="username" />
                                
                            <label><spring:message code="password"/></label>
                            <input id="password" type="password" name="password" />
                            
                            <c:if test="${param.error != null}">
                                <div>
                                    <label><spring:message code="wrongLogin"/></label>
                                </div>
                            </c:if>
                            <c:if test="${param.logout != null}">
                                <div class="alert alert-success">
                                    <label><spring:message code="logoutSuccessfull"/></label>
                                </div>
                            </c:if>
                            
                            <input class="login-button" name="submit" type="submit" value="<spring:message code="submit"/>"/>
                                                            
                        </form>
                    </div>           
                    <div class="bottom-log-in">
                    </div>       
                </div>                            
                
                <input id="wrongLogin" type="text" value="<spring:message code="wrongLogin"/>" style="display: none;"/>
                <input id="logoutSuccessfull" type="text" value="<spring:message code="logoutSuccessfull"/>" style="display: none;"/>
                                    
            </div>
        </div>        
    </body>
    </html>
    6. Finally, create your translation files and add them to the location specified at the end of step 3, in the element <beans:property name="basename" value="classpath:/co/myCompany/myApp/shared/i18n/MyAppResources" />. In my case, this would be in the package src.co.myCompany.myApp.shared.i18n/:
    6.1 MyAppResources_en.properties
    Code:
     
    userName = User
    password = Password
    login = User Login
    submit = Login
    wrongLogin = Wrong user or password!
    logoutSuccessfull = Successful logout!
    6.2 MyAppResources_es.properties
    Code:
     
    userName = Usuario
    password = Clave
    login = Ingreso de Usuarios
    submit = Ingresar
    wrongLogin = Usuario o clave incorrectos!
    logoutSuccessfull = Fin de sesión exitoso!
    I hope newbies like me will benefit from this!

    #2
    Ah, yes... dependencies... here is my pom.xml, in case ypu are working with Maven:
    Code:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
          <groupId>BMSimulator</groupId>
        <artifactId>BMSimulator</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>BMSimulator</name>
      
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <servlet.api.version>3.1.0</servlet.api.version>
            <jstl.version>1.2</jstl.version>
            <smartgwt.version>5.1-p20160127</smartgwt.version>
            <dbcp.version>1.4</dbcp.version>
            <gwt.version>2.7.0</gwt.version>
            <hsqldb.connector.version>2.3.3</hsqldb.connector.version>
            <spring.version>4.2.4.RELEASE</spring.version>
            <spring.security.version>4.0.3.RELEASE</spring.security.version>
        </properties>
      
        <build>
        
            <sourceDirectory>src</sourceDirectory>
            <testSourceDirectory>test</testSourceDirectory>
        
            <resources>
                <resource>
                    <directory>src</directory>
                    <excludes>
                        <exclude>**/*.java</exclude>
                    </excludes>
                </resource>
            </resources>
      
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.3</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
            </plugins>
            
        </build>
      
        <dependencies>
           
               <!-- Servlets -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>${servlet.api.version}</version>
            </dependency>
    
            <!-- JSTL for JSP page -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>${jstl.version}</version>
            </dependency>
    
            <!-- Core: SmartGWT -->
            <dependency>
                <groupId>com.isomorphic.smartgwt.pro</groupId>
                <artifactId>smartgwt-pro</artifactId>
                <version>${smartgwt.version}</version>
            </dependency>
            
            <dependency>
                <groupId>com.isomorphic.smartgwt.pro</groupId>
                <artifactId>isomorphic-sql</artifactId>
                <version>${smartgwt.version}</version>
            </dependency>
                    
            <!-- Additional SmartGWT Dependencies: DBCP -->
            <dependency>
                <groupId>commons-dbcp</groupId>
                <artifactId>commons-dbcp</artifactId>
                <version>${dbcp.version}</version>
            </dependency>
            
            <!-- Core: GWT-->
            <dependency>
                <groupId>com.google.gwt</groupId>
                <artifactId>gwt-servlet</artifactId>
                <version>${gwt.version}</version>
            </dependency>
               
              <!-- DB: HSQLDB -->
            <dependency>
                <groupId>org.hsqldb</groupId>
                <artifactId>hsqldb</artifactId>
                <version>${hsqldb.connector.version}</version>
            </dependency>
    
            <!-- Security: Spring Core -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${spring.version}</version>
            </dependency>
    
            <!-- Security: Spring Security -->
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-config</artifactId>
                <version>${spring.security.version}</version>
            </dependency>
            
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-web</artifactId>
                <version>${spring.security.version}</version>
            </dependency>
    
        </dependencies>
    
    </project>

    Comment

    Working...
    X