Java

java programming

Belajar Spring Security Sederhana

Beberapa hari yang lalu, gw ditanya oleh salah seorang temen gw, Ariestania Winda. Dia nanya, gimana caranya bikin validasi login sederhana dengan Spring Security. Oke, berikut adalah tutorial yang gw kasih ke dia. Semoga bisa bermanfaat untuk yang lain.

Semua dimulai dengan konfigurasi maven sederhana, berikut pom.xml yang gw punya,

<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>com.edw</groupId>
    <artifactId>SpringSecurityExample</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>

    <name>SpringSecurityExample</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>runtime</scope>
        </dependency>
        
        <!-- Spring 3 dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency> 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
        
        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>3.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>3.2.5.RELEASE</version>
        </dependency>
        
        <!-- slf4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.6</version>
        </dependency>
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.1</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
                            <silent>true</silent>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>javax</groupId>
                                    <artifactId>javaee-endorsed-api</artifactId>
                                    <version>6.0</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Kemudian register konfigurasi spring di web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml, /WEB-INF/applicationSecurity.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!-- Spring Security -->
    <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>
    
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

Dan 3 xml milik Spring, ApplicationContext.xml, dispatcher-servlet.xml dan applicationSecurity.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <context:annotation-config/>
    
    <context:component-scan base-package="com.edw.springsecurityexample.controller"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">


    <!-- the mvc resources tag does the magic -->
    <mvc:resources mapping="/css/**" location="/css/" />
    <mvc:resources mapping="/js/**" location="/js/" />
    <mvc:resources mapping="/img/**" location="/img/" />
    
    <context:component-scan base-package="com.edw.springsecurityexample.controller" />
	
    <mvc:annotation-driven />

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<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-4.0.xsd
	http://www.springframework.org/schema/security
	http://www.springframework.org/schema/security/spring-security-3.2.xsd">
    
    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/admin/**" access="hasRole('ROLE_USER')" />
        <intercept-url pattern="/" 	access="isAnonymous()"/>
        <form-login login-page="/" 
                    authentication-failure-url="/?error=1" 
                    default-target-url="/admin/index" always-use-default-target="true"/>
        <logout logout-url="/logout" logout-success-url="/" />
    </http>
 
    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="edw" password="123456" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
    
    
</beans:beans>

Lalu gw bikin satu java class sebagai controller,

package com.edw.springsecurityexample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class IndexController {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index() {
        return "index";
    }
    
    @RequestMapping(value = "/admin/index", method = RequestMethod.GET)
    public String adminIndex() {
        return "adminIndex";
    }
}

Kemudian satu jsp sederhana sebagai halaman login,

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>Hello Spring MVC!</h1>
        <h2>Tolong Login Dulu </h2>
        
        <c:if test="${not empty param.error}">
                <div style="color: red;">
                    Username atau Password Salah
                </div>
        </c:if>
        
        <form action="j_spring_security_check" method="POST">
            <table>
                <tr>
                    <td>
                        username
                    </td>
                    <td>
                        <input name="j_username" type="text" />
                    </td>
                </tr>
                <tr>
                    <td>
                        password
                    </td>
                    <td>
                        <input name="j_password" type="password" />
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <input name="submit" type="submit" />
                    </td>
                </tr>
            </table>
        </form>
    </body>
</html>

Dan halaman admin sederhana, yang hanya bisa diakses apabila sudah login yang isinya link logout.

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head><a href="http://edwin.baculsoft.com/wp-content/uploads/2014/11/springsecurity-login-gagal.png"><img src="http://edwin.baculsoft.com/wp-content/uploads/2014/11/springsecurity-login-gagal.png" alt="springsecurity login gagal" width="458" height="287" class="aligncenter size-full wp-image-1535" /></a>
    <body>
        <h1>Selamat, anda sudah login -- admin page</h1>
        <br />
        <a href="${pageContext.request.contextPath}/logout">logout</a>
    </body>
</html>

Berikut adalah tampilan struktur netbeans project
springsecurity project structure

Tampilan halaman login, dan tampilan jika login gagal,
springsecurity login

springsecurity login gagal

Jika login dengan username edw dan password 123456, maka akan tampil halaman seperti berikut,
springsecurity login sukses

Source lengkapnya, bisa diakses di github saya, di url ini.

How To Fix Glassfish’s Exception “only one instance running in the cluster”

Recently ive met a new exception on my Glassfish 3.1 log file, here is the complete stack trace

[#|2014-10-09T13:22:09.248+0700|INFO|glassfish3.1.2|
org.shoal.ha.cache.command.load_request|_ThreadID=301;_ThreadName=Thread-2;|
Skipped Loading of 396544c17b8bbbc620000f9b2196 since there is only one instance running in the cluster.|#]

Because of this error, somehow im unable to do a session failover on my Glassfish.

Using asadmin get-health show that my instance are both healthy and alive

glassfish3>asadmin get-health
Enter the value for the clusterName operand> cluster1
instance1 started since Thu Oct 09 16:43:21 ICT 2014
instance2 started since Thu Oct 09 16:45:40 ICT 2014
Command get-health executed successfully.

but both instances started not at the same time.

So what i do is very simple, i restarted my cluster so both of my instances started at the same time. And somehow, my error is gone and i can do failover seamlessly.

restart glassfish cluster

A Weird Error At Glassfish, “Class [ java/lang/AutoCloseable ] not found.”

Today i’ve found a very weird error on my Glassfish 3.1, here is the complete stack trace

[#|2014-10-09T10:54:02.685+0700|SEVERE|glassfish3.1.2|global|_ThreadID=24;_ThreadName=Thread-2;
|Class [ java/lang/AutoCloseable ] not found. 
Error while loading [ class com.edw.dodol.service.MyService ]|#]

Im using SpringMVC and the error affect all my service classes, so somehow my application is unable to start.
After trying several solution, i found out that my JAVA_HOME variable are still pointing to a JDK6 version, while my application need at least JDK7.

Changing my JAVA_HOME variable into JDK7 solve this issue.

A very weird error actually, usually running an application under a different SDK version will create a “Major-Minor Version Exception”, but somehow i cant see that error anywhere 🙁

Changing JBoss 5 Admin Console Username and Password

JBoss 5 Admin Console username is very default, it is admin and admin. Therefor i am trying to change it to increase the security of my jboss application.

I thought that it is very easy to change the password, but apparently it not. I need to manually change the content of a properties file instead of a simple change password form.

Okay, so basically i need to change the content of jmx-console-users.properties file, which located at

<JBOSS_INSTALLATION_FOLDER>/server/default/conf/props

jboss console

you will see, admin=admin. Changing it, will change the username and password needed to login into jboss admin console.

Hope it can help.

ps.
thank you to my friend, Molly Nella Septiandini who have helped me solved this issue 😉

Building A Runnable Maven JavaSE Desktop Application And Including Its Jar Dependencies

Usually it’s very easy to create a runnable jar using Netbean’s ant plugin, but on this project im trying to utilize maven. One painfull thing is somehow maven is unable to build create a runnable jar file which included its jar dependencies.

After several minutes googling, i’ve found a very good solution. Here is the content of my pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>com.edw</groupId>
    <artifactId>Edw</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>        
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${targetdirectory}</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>                            
                            <classpathPrefix>lib/</classpathPrefix>                            
                            <mainClass>com.edw.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <descriptors>
                        <descriptor>src/main/assembly/customAssembly.xml</descriptor>
                    </descriptors>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id> 
                        <phase>package</phase> 
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

And dont forget, adding an xml file, customAssembly.xml which located on src/main/assembly/ folder

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>bin</id>
    <formats>
        <format>zip</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}/dependency</directory>
            <outputDirectory>lib</outputDirectory>
        </fileSet>
    </fileSets>
</assembly>

Just build your application from Netbeans, and you will find a zip file on your Netbeans’ target folder, which consist of a runnable jar file and a lib folder containing your jar dependencies. 😉