Monday, December 13, 2010

OpenID + Spring MVC 3 + Spring Security 3 + OpenID Selector

We decided to move our authentication into openID. Meanwhile, we upgrade our security from Spring Security 2 to 3. Adding OpenID to spring security is straightforward, add the following tag into "<http>" tag of security.xml
<openid-login login-page="/login.jsp" login-processing-url="/openlogin" user-service-ref="userDao"
                 authentication-failure-handler-ref="openIdAuthFailureHandler"/>

And OpenID will take over the authentication.

However, there are more to change for openID.

First and most obviously, we need a new login page takes user to openid provider instead of our own user/password checker. We chose openid-selector (1.2 currently) as the spring security choose it for demo. It is a fairly nice package. It allows one to choose from several openid providers (Google, Yahoo, AOL, OpenID, blogger, flicker, ...) Several things need to be done to use it:


  • However, it uses jQuery and has lots of conflict with prototype we are using. Fortunately, the conflict originates mostly from "$". I modify the two js file, replace all "$" with "jQuery" and add jQuery.noConflict(); in the beginning and firebug stops to complain.


  • There are several options in openid-jquery.js to play with. I use default mostly, except "no_sprite" to true as I have uncomment flickr and its not in the big sprite picture.


  • In the login page, add following into "<head"> tag (notice that openid-jquery.js should be add before openid-jquery-en.js)
    <script type="text/javascript" src="<c:url value="/scripts/jquery/openid-selector/js/openid-jquery.js" />"></script>
         <script type="text/javascript" src="<c:url value="/scripts/jquery/openid-selector/js/openid-jquery-en.js" />"></script>

    and add following into "<body">
    <script type="text/javascript">
            jQuery.noConflict();
            jQuery(document).ready(function(){
                openid.img_path="<c:url value='/scripts/jquery/openid-selector/images/'/>";
                openid.init("openid_identifier");
                jQuery("#openid_identifier").focus();
            });
        </script>

    Notice the openid.img_path has to be set outside if the openid-selector files are not put under the root.

These pretty much take care of login. But now we also need to modify signup process. Originally, you click signup and then put a new username/password. Now with openid, you first login with an openid from one of the providers, system found that you are not a user, and provide you a signup sheet. That is why in above <openid-login"> tag, we need a special "openIdAuthFailureHandler" for "authentication-failure-handler".

We can extend a spring handler for this purpose.
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.imirsel.nema.webapp.security;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.openid.OpenIDAuthenticationStatus;
import org.springframework.security.openid.OpenIDAuthenticationToken;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

/**
 *  Customized {@link AuthenticationFailureHandler} that redirect to sign-up page
 * if the OpenID authentication succeeds, but the user name is not yet in local DB of the container
 * @author gzhu1
 */
public class OpenIDAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    static private Log logger = LogFactory.getLog(OpenIDAuthenticationFailureHandler.class);

    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
            HttpServletResponse response, AuthenticationException exception)
            throws IOException, ServletException {
        logger.error(exception, exception);
        if (exception instanceof UsernameNotFoundException
                && exception.getAuthentication() instanceof OpenIDAuthenticationToken
                && ((OpenIDAuthenticationToken) exception.getAuthentication()).getStatus().equals(OpenIDAuthenticationStatus.SUCCESS)) {
            DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
            request.getSession(true).setAttribute("USER_OPENID_CREDENTIAL", exception.getAuthentication().getPrincipal());
            // redirect to create account page

            logger.info("user (" + exception.getAuthentication().getPrincipal() + "," + exception.getExtraInformation() + ") is not found and redirect to signup.");
            redirectStrategy.sendRedirect(request, response, "/signup.html");

        } else {
            super.onAuthenticationFailure(request, response, exception);
        }
    }
}

and declare the bean in applicationContext.xml.
<bean id="openIdAuthFailureHandler" class="org.imirsel.nema.webapp.security.OpenIDAuthenticationFailureHandler">
        <property name="defaultFailureUrl" value="/login.jsp"/>
    </bean>

Of course, now I do not really have a password, so I generate a random string for password, because a password is needed somewhere else.

That is it. Now your user can sign-in with their Google, Yahoo, AOL, open-id account directly.

Tuesday, December 7, 2010

My Review of HP G62-340US 15.6" Laptop

Originally submitted at Staples

Now you can do more and have more fun without spending more. The HP G62 notebook PC features the latest technology and enhanced security right out of the box for the perfect balance of performance, connectivity, and worry-free computing. With its cl ean design and textured HP Imprint finish in char...


Solid buy

By zggame from urbana, IL on 12/7/2010

 

5out of 5

Pros: Quiet, Quality Display

Best Uses: Web Browsing, Video, Word Processing

Describe Yourself: Tech Savvy

Primary use: Personal

I bought at the sale for $379-$50 coupon for my parents. It has HDMI and webcam. They mostly just use skype, web browsing and watch online streaming TV/movie. It is perfect for their usage. The thrown in office starter is not bad. HDMI is easy for them to connect TV to watch video, better than VGA+audio port. Webcam works fairly well during skype. Overall, it is plenty for them. Great buy. Not too many bloatware. Norton is annoying for the trial. I uninstalled it and put a free Avast Personal. Office starter should be more than enough for some basic use.

(legalese)

Wednesday, October 13, 2010

Set optional jetty-env.xml for JNDI in maven jetty plugins

I talked about how to set up jndi with jetty in last post. But I still like to use "jetty:run" in the maven jetty plugin. It uses an embed server that hard to configure. Later I found a way to specify a non-conventional position for jetty-env.xml in maven-jetty-plugin. So I put jetty-env.xml in that position and specify it in pom.xml. Now I can still use jetty:run. But when it packaged as war and deployed in web container. It cannot run without setting JNDI in server.

Here is my setting:
1. Put jetty-env.xml in WEB-INF/local/jetty-env.xml;
2. Add following into pom.xml

<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.22</version>
<configuration>

<contextPath>/</contextPath>

<jettyEnvXml>src/main/webapp/WEB-INF/local/jetty-env.xml</jettyEnvXml>
.......
</configuration>
</plugin>


Well, if you really hate any settings in svn repository. You can put jetty-env.xml somewhere outside svn directory. Use

<jettyEnvXml>${jetty.setting}</jettyEnvXml>

Now when you start maven append the system property jetty.setting=directory.

mvn -Djetty.setting=**/jetty-env.xml jetty:run

Friday, October 8, 2010

Use JNDI with Spring/Jetty

We used to bury the settings (databases, remote calls urls, ...) in Maven's setting.xml. We keep several profiles for settings for different servers and use maven's profile selector to switch between them. This approach hide the sensitive information (username/password to databses...) in our local machines and switch between different profiles fairly effectively. However, it is painful to keep settings.xml sync between us, especially when we changes setting in server pretty frequently. So we decide to move to JNDI, so the setting goes with the servlet server (Jetty now, maybe some more powerful stuff later) and no more sync problem.

It took me three full days! Unfortunately, it becomes another typical experience with the Configuration Nightmare. One spends hours after hours read stuff all over internet and nothing makes sense, until finally, it makes sense and actually is QUITE SIMPLE!

Two pages are mostly useful. Jetty's JNDI page and this one (a little out-of-date and a few flaw).

So set up the resources in JNDI first. We need two types: DataSource for databases and normal Strings for remote call urls.

1. First of all, jetty by default does not support jndi. So we need to tell jetty to turn it on. (Modify your etc/jetty.xml file.)
<Array id="plusConfig" type="java.lang.String"> -->
   <Item>org.mortbay.jetty.webapp.WebInfConfiguration</Item>
   <Item>org.mortbay.jetty.plus.webapp.EnvConfiguration</Item>
   <Item>org.mortbay.jetty.plus.webapp.Configuration</Item>
   <Item>org.mortbay.jetty.webapp.JettyWebXmlConfiguration</Item>
   <Item>org.mortbay.jetty.webapp.TagLibConfiguration</Item>
 </Array>

<Call name="addLifeCycle">
     <Arg>
       <New class="org.mortbay.jetty.deployer.WebAppDeployer">
         <Set name="contexts"><Ref id="Contexts"/></Set>
         <Set name="webAppDir"><SystemProperty name="jetty.home" default="."/>/webapps</Set>
   ......
        <Set name="configurationClasses"><Ref id="plusConfig"/></Set>
       </New>
     </Arg>
   </Call>


Alternatively, one can turn it on in one particular webApp, but that is kind of complicated, and we would like resources configured in server level. So this works fine for us.

2. Adding the resources.
Create a xml file (myjndi.xml) and put it along with jetty.xml in jetty.home/etc.
<Configure  id="Server" class="org.mortbay.jetty.Server">
<New id="dataSource" class="org.mortbay.jetty.plus.naming.Resource">
        <Arg>jdbc/dataSource</Arg>
        <Arg>
            <New class="org.apache.commons.dbcp.BasicDataSource">
                <Set name="driverClassName">com.mysql.jdbc.Driver</Set>
                <Set name="url">jdbc:mysql://localhost:3306/diy090?autoReconnect=true</Set>
                <Set name="username">user</Set>
                <Set name="password">pass</Set>
                <Set name="maxActive">100</Set>
                <Set name="maxWait">1000</Set>
                <Set name="poolPreparedStatements">true</Set>
                <Set name="defaultAutoCommit">true</Set>
            </New>
        </Arg>
    </New>
    
    <New class="org.mortbay.jetty.plus.naming.EnvEntry">
        <Arg>flowservice/url</Arg>
        <Arg type="java.lang.String">rmi://remote.service.call:1099/FlowService</Arg>
        <Arg type="boolean">true</Arg>
    </New>
.......
</configure>

This will add the resource ("java:comp/env/jdbc/dataSource", "java:comp/env/flowservice/url") in the server level that available to every web applications. Note that "id" attribute in configure tag needs to match "id" attribute in jetty.xml so jetty know they are for the same server.
Now instead of starting jetty by "java -jar start.jar", we need to tell jetty to use both the default setting (etc/jetty.xml) and extra xml (myjndi.xml), the command is "java -jar start.jar etc/jetty.xml etc/myjndi.xml". Or we can simply put the content of <configure> tag into jetty.xml. Then one can use the same old command "java -jar start.jar".

Alternatively one can created a xml file called jetty-env.xml with the resource and put it along with web.xml in WEB-INF. This supplies the info only for that particular web application. But now one should use instead

<Configure class="org.mortbay.jetty.webapp.WebAppContext">


Note: to make the data source work, relevant jars need to be in jetty's library jetty.home/lib/ext. For common dbcp with mysql. Here is the list:
commons-dbcp-1.2.1.jar
commons-collections-3.2.jar
commons-pool-1.2.jar
mysql-connector-java-5.1.6.jar



3. Now the normal objects (String, "java:comp/env/flowservice/url") are exposed to web application now. But datasource is not yet. (That took me more than a day to figure out/realize.) One has to declare it in web.xml of web application.

<resource-ref>
<res-ref-name>jdbc/dataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>


4. Spring provided the new tag that is much easier to work with than previously.

<jee:jndi-lookup jndi-name="java:comp/env/jdbc/dataSource" id="dataSource" />

<jee:jndi-lookup jndi-name="java:comp/env/flowservice/url" id="flowserviceUrl" />

That is it. Now you have two beans dataSource(java.sql.DataSource) and flowserviceUrl(String) ready for anything you likes.

Friday, September 17, 2010

SVN Merge is Evil

It is really hard. I worked on a branch for a new feature maybe 2 months. The trunk is kept with some small enhancement and bug-fix. Today is the merge day. OMG, that is hard. I used the merge in Netbeans first. After 40 minutes I seem to get all the brown sign of conflicts out and committed it. Well, that is not so bad, I thought. But soon I discovered quite some new files are missing and some are not updated. Boom! I rolled things back to last reversion and recommitted. This time I tried to do it in Eclipse. Well, it seems more conflicts pop up and I guessed that Eclipse's SVN plugin was better. I was wrong after another half an hour. Still some files were showed updated but they are definitely old. What is wrong!

It turns out that neither one handles TREE-CONFLICTs well. And yes, it proliferates for my merge. And neither provides any good way to handle it. I have to done it one at a time in command line. SVN is really dumb for tree-conflict. I checked out a clean reversion again. I merged once. It stops at certain revision. I resolved conflicts (normal ones) in Eclispe. Then I tried to hand-mark those tree-conflict as resolved. And then I merged again. This time it progressed to some further revision with some new conflicts. I marked them resolved again, merged again. .... Five, six cycles later, I finally get to the HEAD. :) The stupid things about svn is that if I added one file and later removed it in the branch, merging stops at some revision with adding the file, then next time merging removes it. Odd price to pay with a revision system with historical approach.

That is really hard!

Note: A couple of days later, I found it missed a few files. OMG! (9/20)

Tuesday, August 31, 2010

Name Parameter in HQL of Hibernate

Name Parameter in HQL is nice, like the parameter statement in sql, it is more robust than build the hql in flight and for the special characters. But it is also a little picky. It took me about 30 minutes to figure out what is wrong and the correct combination.


Session session=getSession();
String hql="from Job where (ownerId=:userId) AND ((name LIKE :keyword) OR (description LIKE :keyword) "
+" OR (flow.name LIKE :keyword) OR (flow.description LIKE :keyword)"
+"OR (flow.typeName LIKE :keyword) OR (flow.keyWords LIKE :keyword))";
Query query=session.createQuery(hql);
query.setLong("userId", userId).setString("keyword", "%"+keyword+"%");


You cannot put flow.keyWords LIKE '%:keyword%' or flow.keyWords LIKE %:keyword% in the hql, it has to go in the setString().

Tuesday, August 24, 2010

Switch to Netbeans

I get fairly frustrated by Eclipse. It is nice and polished in most sense. However, a few things keep bothering me. A few essential tools in our work needs plugins. Svn and maven plugins are both problematic. Early this year, for some reason, svn plugin keeps freezing the eclipse. Maven plugin also feels somehow weird. I did not get it through until I start to use spring's Spring Tools Suite(STS), a customized eclipse from spring source. It is kind of nice with maven built-in. I still need to install svn plugin, which does not freeze anymore. But the svn commit often fails, not sure whether I should blame the plugin or the googlecode's svn repository though. But it is likely some suboptimal setting in svn plugin. However, maven plugin (M2eclipse) still runs sluggishly and occasionally it freezes STS, especially in the MacBook Pro (4G Ram, 2.4G T8300). It often takes 10 seconds or more to open a pom.xml files, even in a fairly powerful machine ( 2.4G Core Quad, 8G Ram). Our projects are reasonably complicated, dependency in the order of 100 things. It has some nice tool for maven, such as the search in dependency. But the speed is too slow. It takes even 10 seconds to switch to a window of pom.xml. Something seriously wrong with m2eclipse.

Recently Eclipse upgrade to 3.6. I tried to upgrade. But it does not work well for me. Some common shortcut key does not work such as Ctrl-Alt-C for commit.

I don't remember how it starts. I saw netbeans a few days ago. I used netbeans before eclipse. But it is a long time ago. In recent few projects, everyone else use s eclipse, so I use it as well. Well, I took a serious look at netbeans (6.9.1) this time, to my pleasure, it has maven and svn built-in. So it should be OK for my project. Our project is a multi-module maven project. I first thought the project is eclipse specified as we commit from eclipse. And I know for sure that there are some eclipse's setting in repository. I tried netbeans and it works. It actually works pretty better than I thought. It checkout the project into several projects, each module becomes a project. It actually is better, as now each project's default paths (src/test/web/res/..) are recognized automatically into the project viewer. In eclipse, it is one project and eclipse cannot recognize the default maven paths in modules. So they are all normal folders and it is quite inconvenient to look for the path I need within about 10 different folders. One plus. Well, soon I found a few other goodies. It automatically include the default ~/.m2/settings.xml into the project. This is fairly convenient because it does control quite some properties in the project and I often needs to modify it. And best of all, pom.xml opens fast. In the crude looking, it is treated as a simple xml file. And a close look shows that you can also open a dependency graph, which does take some time. But most time, I do not need to see that, I only need to work with it as simple xml.

Svn is not as powerful. It does not provide a svn repository view. However, you can checkout things and other normal tools like update, commit, merge, diff are there and that is enough for me.

And an extra plus is that it seems bundled with Spring. And I got some basic tools for spring out of box, such as bean editor...

Overall, netbeans seems to run faster. It does not looks as nice, swing is not as good as SWT. But it looks OK, and this is the secondary concerns for me. Things seems integrated more tightly in netbeans. Eclipse seems more module, everything comes in as plugin and there are lots of great plugin. But for my work, I only need those typical tools. And netbeans seems to serve me better.

I switched to netbeans and it works fine for me for a week now . We will see how it works out in more time.


Update: Dec. 16th, 2010
Two good things about Netbeans:
* It formated HTML corrected. You will definitely hate Eclipse/sprinesource when you try to auto-format html. Netbeans also take care of javascript in html <script> tag.
* Netbeans also understand javascript syntax to some degree and points out some obvious typo such as extra ";", "}", ... Javascript is nice, but hard to debug and often a small typo like that costs me half an hour as firebug/chrome developer tool does not realize it and reports some other errors and leads you everywhere but the correct place. That is a really benefit with Netbeans.