Spring MVC + Security Note (3) – About the Role Name

By WZH.

In the last two examples we see that user has a role define called ROLE_USER

<user     name=”mkyong”
password=”123456″
authorities=”ROLE_USER” />

<intercept-url pattern=”/admin**” access=”ROLE_USER” />

 

You should note that ROLE_USER here is a string only.  Just need to matched the authorities later in the  Authentication part.  Authentication provider give this role and it matched with the login part request, then this role will will assigned to this principle after authentication.

You can define any role by your self. Only ROLE_ANONYMOUS is a predefined role name in the spring security to an anonymous user.

Inside Spring, the default AccessDecisionManager (which interprets the access attributes that you specify in the intercept-url element) uses a RoleVoter implementation. By default this looks for the prefix “ROLE_” on the attribute, so your best option is to make sure that your roles have this prefix.

If you want use another prefix, . eg AAA_USER, you have to define a custom AppVoter:

<bean class=”org.springframework.security.vote.RoleVoter”>
<property name=”rolePrefix” value=”AAA”/>
</bean>
you need to read more on how to do this thing.

Advertisements

Spring security note – Create a simple authentication-manager by get user from DB table – 1

By WZH. Aug 2016

We want authenticate user against with a DB rather from a hard code user service with username and password. So system can work like a production system.

Refer to this article and its code:

http://www.mkyong.com/spring-security/spring-security-form-login-using-database/

Here is key points:

        <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, role from user_roles where username =?  " />
        </authentication-provider>

users-by-username-query and users-by-username-query are two queries that to get user + password   and user + role from DB.  You do not need to use exactly field names for these in DB define , but SQL return data should there 3 items in order for users and 2 items in order for authorities.

After you make this part correct and your DB ok, you should be able to implement authenticate from DB easily. But this password could be clear pass save in DB.

Question – what if your password field is MD5 of real password in DB to ensure security how to do it in Spring security?

Let me show you one example that what you should do, add this line at <authentication-provider> first:

<authentication-provider>
            <password-encoder hash="md5"/>
            <jdbc-user-service data-source-ref="mySQLDataSource"
                users-by-username-query=
                    "select loginId, password, true from users where loginId=?"
                authorities-by-username-query=
                    "select loginId, authority from user_roles where loginId =?  " />
        </authentication-provider>

<password-encoder hash=”md5″/> will tell spring security that password read from DB is MD5 hash.  So spring will compare MD5 of the LoginForm input password with the MD5 read out from DB to do the authentication. But when you create/ register a new user into your DB, you need to calculate the MD5 by your code. You have to ensure your MD5 hash result is same with Spring.

Remember this piece of code:

PasswordEncoder encoder = new Md5PasswordEncoder();
String hashedPass = encoder.encodePassword("origClearPassword", null);

then you can save hashedPass to you DB as the “password” for hashed authentication.

 

Refer too:

http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html

 

 

 

Spring MVC + Security Note (1) – Basic custom login

By WZH

Spring MVC normally is not hard to implement but to add on the security part naturally using Spring Security which in fact  needs a lot readings for reference. So here I made some notes for some fundamentals to start implement the Spring Security on MVC. Referenced from this article

http://www.mkyong.com/spring-security/spring-security-form-login-example/

you can download this project from end of the article. Here I give the major explain that key points for spring security login.

Get Spring security jars

        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</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>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>3.2.5.RELEASE</version>
        </dependency>

 

Create a XML. eg spring-security.xml and put it together with web.xml(remember include this file for contextConfigLocation)

<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-3.2.xsd">

    <http pattern="/login.htm*" security="none" />
    <http auto-config="true">
        <intercept-url pattern="/admin**" access="ROLE_USER" />
        <form-login login-page="/login" 
            default-target-url="/welcome"
            authentication-failure-url="/login?error" 
            username-parameter="username"
            password-parameter="password" />
        <logout logout-success-url="/login?logout" />
    </http>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user   name="username" 
                        password="123456" 
                        authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

</beans:beans>

 

<http pattern=”/login.htm*” security=”none” />

This is exclude one URL or one page from the security control. You can have multiple <http for these.

<intercept-url pattern=”/admin**” access=”ROLE_USER” />

define what kind of URL need to secured and what Role needed to access these URL.

<form-login  define how the form login works, which URL for login, login error, after login page, etc.

<logout define after logout ok, go to which url.

<authentication-provider page define the user and password is got from where to do the authentication. Now a hard coded user is there. After user is authenticated, he will have the authorities=”ROLE_USER”.

Now we have done config define for the Spring security, we need to define pages and controllers for it.

In the Login page:

        <form name='loginForm'
            action="<c:url value='/j_spring_security_check' />" method='POST'>

            <table>
                <tr>
                    <td>User:</td>
                    <td><input type='text' name='username'></td>
                </tr>
                <tr>
                    <td>Password:</td>
                    <td><input type='password' name='password' /></td>
                </tr>
                <tr>
                    <td colspan='2'><input name="submit" type="submit"
                        value="submit" /></td>
                </tr>
            </table>

        </form>

html inputs name for user name and password, must match with the <form-login data

username-parameter=”username”
password-parameter=”password”

/j_spring_security_check   is the URL supplied by Spring security to do the authentication for you. At admin.jsp (for logout), you will see that log out URL is /j_spring_security_logout

 

Basically these are key points to make the custom login works in spring security.

 

 

The idle mySQL connection pool closed issue

By WZH

This was one issue that faced sometimes when you forget something in the system config. Log it as it might help reminding in future.

Issue:

After several hours or days no body using system, the first user try to login and always failed, until several times trying.

Reason:

A further check the log found error of  java.sql.SQLException: Connection already closed.

So the real real is that JDBC connection pooling is closed after too long time idle.

Solution:

DB has ability to run a  validationQuery to detect the connection closed or not.  If the validation query fails, the bad/closed connection is dropped and another connection is created to replace it. So it will ensure connection is ready before a code query.

The validation query is a query run by the data source to validate that a Connection is still open before returning it.

For my MySQL case, you need to add this for the JDBC define in the Spring config:

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
 destroy-method="close">
    ............................
    ...........................
    <property name="validationQuery" value="select 1"/>
</bean>

 

Refer to :

http://commons.apache.org/proper/commons-dbcp/configuration.html
http://stackoverflow.com/questions/3668506/efficient-sql-test-query-or-validation-query-that-will-work-across-all-or-most

 

How to consume json object from Spring MVC controller input directly

By WZH

This is small note about the json input directly to Spring MVC controller side, jackson will auto convert it to Java object you want:

  1. Make sure has this jar added

 <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.0</version>
  </dependency>

2.  Controller side

@RequestMapping(value = urlPatternController, method = RequestMethod.POST)
public @ResponseBody Person createPerson(@RequestBody Person jsonString) {
   Person person=personService.savedata(jsonString);
   return person;
}

@RequestBody – Covert Json object to java
@ResponseBody– convert Java object to json

3. JS client side :

 

$.ajax("<%=path%>/web/urlPatternController", {
                           type:'POST',
                           dataType: 'json',
                           data: person
                    })

 

Link can be refered

 

 

Improve the Mybatis performance

By WZH

Some tips on improve the Mybatis performance.

  1. Set fetchSize to a considerable amount.
  2. Only retrieve needed columns from DB and map them to the Java object.
  3.  Try to reduce the nested selects in one user interaction, try to use more nested joins  in the SQL level in one time DB call.
  4.  Use cache integration to improve re-read speed.  Such as Memcached or  Ehcache
  5. SQL  and DB self optimization, such as index for sort and order

 

 

How to run Memcached on Mybatis

By W.ZH

1. Install Memcache

To start, install memcached via apt-get. such as in the Ubuntu 12.04

sudo apt-get install memcached

It auto starts the memcached

ps -ax | grep memcac
21199 ?        Sl     0:00 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1

Refer to official Mybatis link:  http://mybatis.github.io/memcached-cache/
Add the jar to your maven

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-memcached</artifactId>
    <version>1.0.0</version>
  </dependency>
 and then add the memcached to your mapper if you want which MyBatis mapper to use it.
<mapper namespace="org.acme.FooMapper">
  <cache type="org.mybatis.caches.memcached.MemcachedCache" />
  ...
</mapper>
Create a memcached.properties file and put to your class path, eg resources folder.
# any string identifier
org.mybatis.caches.memcached.keyprefix=_mybatis_
# space separated list of ${host}:${port}
org.mybatis.caches.memcached.servers=127.0.0.1:11211
org.mybatis.caches.memcached.connectionfactory=net.spy.memcached.DefaultConnectionFactory
org.mybatis.caches.memcached.expiration = 600
org.mybatis.caches.memcached.asyncget = true
# the expiration time (in seconds)
org.mybatis.caches.memcached.timeout = 600
org.mybatis.caches.memcached.timeoutunit = java.util.concurrent.TimeUnit.SECONDS
# if true, objects will be GZIP compressed before putting them to Memcached
org.mybatis.caches.memcached.compression = false

In fact if you add multiple cache server at org.mybatis.caches.memcached.servers, it will has fail over ability among them. auto continue using live one if one die.

This intergration in fact based on the Spymemcached, is an asynchronous supported, single-threaded Memcached client. When you call any caching-related method on spymemcached’s MemcachedClient, it will be handled asynchronously. The client call method handles writing the details of the operation that should be performed into a queue and returning the control back to the client making the call. The actual interaction with the Memcached server, meanwhile, is handled by a separate thread that runs in the background.

My testing prove that it can improve the loading DB data at least 50% reading time if data has been in memcached. So this also proves that Mybatis self cache is not enough  big because it is not designed for cache only.