Tuesday, May 15, 2012

Automatic sign in after registration in Spring Security


I have a program that requires user will be automatically signed in after register so they won't be redirected to login page again after registration.

The following codes actually took me quite long time to figure out after read through many internet posts. Eventually I found some codes from stackoverflow.com.
(BTW, I like the name of the site. Perfectly make sense for a programmer.)

    @RequestMapping(value = "login.asp", method = RequestMethod.GET)
    public String doAutoLogin(@RequestParam(value="Email", required=true) String username,
            @RequestParam(value="Password", required=true) String password, HttpServletRequest request) {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);

        Authentication auth = authenticationManager.authenticate(token);

        // Place the new Authentication object in the security context.
        SecurityContextHolder.getContext().setAuthentication(auth);

        //this step is import, otherwise the new login is not in session which is required by Spring Security
        request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());

        return "redirect:home.htm";
    }


To register the authentication manager, put this in the same class:

    @Autowired
    @Qualifier("authenticationManager")
    protected AuthenticationManager authenticationManager;

In the security.xml, you need to set the alias:



    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="registerUserDetailsService">
            <password-encoder hash="md5" />
        </authentication-provider>
        <authentication-provider user-service-ref="registerUserDetailsService"/> <!-- this provider is used to login user from other system, which has encrypted password. -->
    </authentication-manager>

The second auth provider is almost exactly same as the first, except it doesn't require password encoder. I have this provider because we have a link from other system that has encrypted password, so I cannot have it encrypt again here. Otherwise, the password will be encrypted twice so that use cannot login from that link.
Spring will go through all those providers to validate username and password. As long as one of them passes, user will be able to sign in


Thursday, April 26, 2012

An alternative to Spring Security ACL

Spring Security ACL might be good, but the drawback is obvious too:
1. You need to save permission along with saving each business object
2. Need annotation on each method
3. Once you decide to change the permission setup, there is huge work to modify production data; and it is problematic and dangerous
4. You probably have the permission structure in place already. For example, Contract is created by UserA, so only UserA can change it. You will save duplicate info in ACL. Why not just reuse existing structure you already have.

So, I'd like to go back to the traditional Filter. However, I also want to utilize the power of Spring Security. It actually is easy. All you need is to add some configuration below Spring Security configuration in web.xml. The trick here is DelegatingFilterProxy actually access your bean name.

    <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>

    <filter>
        <filter-name>aclSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>myUserAccessFilter</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>aclSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

myUserAccessFilter is just a bean you defined in the Spring applicationContext.xml:

    <bean id="myUserAccessFilter" class="com.foo.MyUserAccessFilter">
        <property name="myUserSerive" ref="myUserService" />
    </bean>

You just need to implement your MyUserAccessFilter like this:

package com.foo;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;

public class MyUserAccessFilter implements Filter{
    protected final Log logger = LogFactory.getLog(getClass());
    
    @Autowired
    private MyUserService myUserService;
    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try{
            User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            String[] contractIds = request.getParameterValues("contractId");

            checkUser(contractIds, currentUser);
            
        } catch(AccessDeniedException e){
            throw e;
        } catch(Exception ignored){
            logger.error(ignored, ignored);
        }
        
        chain.doFilter(request, response);
        
    }
}

Friday, October 14, 2011

25% tip?

I think I grabbed this snapshort from sfgate.com, saying 25% tip is too low or something. Anyway, the problem about this picture is: this picture actually is about a waiter is preparing food for the group dinner of Communist Party in China. 

Wednesday, March 2, 2011

Tomcat 7 hot deploy, rolling upgrade

My client needs their Java web application available 24x7, but you have to restart Tomcat for any Java changes and that bring down the application. Then some users may lose their session and fail to save their data. It can be even worse: user may be in the middle of making payment and then suddenly the user was kicked out, he may have been charged but your system hasn't recorded that.

Fortunately now Tomcat 7 has this revolutionary solution http://tomcat.apache.org/tomcat-7.0-doc/config/context.html.

All you need to do is to
1. keep your old app foo.war untouched
2. name your new version of app to foo##0001.war and upload to webapps folder

The old session will use foo.war, and new user will use foo##0001.war. Here are some details:

  • If no session information is present in the request, use the latest version.
  • If session information is present in the request, check the session manager of each version for a matching session and if one is found, use that version.
  • If session information is present in the request but no matching session can be found, use the latest version.
As Tomcat compare version by comparing string, you have to name your file like foo##0001.war, foo##0002.war, foo##0011.war.
If you name it like foo##11.war and foo##2.war, foo##2.war will be considered newer version than foo##11.war

Sunday, May 9, 2010

edgar mobile

front end can be
1. an iphone app, gphone app, blackberry app, kindle book, nook book, or any other mobile reading device.
2.web browser such as IE, FF. depending on what client is, show different layout for that browser so it gives good comfortable user experience.

--however, to make money, any front end will display ad. because ar/10k is free, u just cannot make money from selling the front end

back end
1. read xbrl from sec
2. save into db.
3. serve the reading request from front end
4. registration service so user can save their reading and seamless switch among any device.

platform
java, tomcat, mysql

Wednesday, April 21, 2010

java email cut off

deleting all non-ascii and control char will fix the problem - this assume you expect English only input.

String truncated = mailBody.replaceAll("[^\\p{ASCII}]", "").replaceAll("\\p{Cntrl}", "");

Followers