Saturday, January 30, 2010

Plaxo OpenID Recipe

Plaxo was probably one of the first main sites where I saw OpenID support for your user credentials. But only today did I notice that they also have a really nice write-up of of their OpenID implementation, which could serve you as a guide/recipe for implementing your own OpenID supporting user registration process.

Check it out at: http://www.plaxo.com/api/openid_recipe

Labels: , ,

Wednesday, January 27, 2010

Automating User Registrations with OpenID and Spring Security 3.0 - Part 3

Preparing heavily for DevNexus 2010, I did not have as much time as I hoped for in order to continue my series on using OpenID with the new SpringSecurity 3.0 (See Part 2 for details) Thus, today I would just like to cut and paste some of the code from my little 'home-POC'. In the coming weeks I still hope to incorporate it properly into jRecruiter.

Here is the JSP snippet for the OpenID login form:
<div id="openid-registration">
  <form name='oidf' action='/jrecruiter-web/j_spring_openid_security_check' method='POST'>
    <fieldset id="openIdLoginSection">
          <legend>Login with OpenID Identity</legend>
          <div class="required">
            <label for="openid_identifier">Identity</label>
            <s:textfield id="openid_identifier" name="openid_identifier" required="true" maxlength="80" tabindex="1" size="30"/>
          </div>
          <div class="submit">
            <input type="submit" value="Login"/>
          </div>
    </fieldset>
  </form>              
</div>


Here is the relevant piece of my Spring context file:

<security:http  auto-config="true" access-decision-manager-ref="accessDecisionManager" >
  <security:intercept-url pattern="/s/admin/**" access="ADMIN"                        requires-channel="https"/>
  <security:intercept-url pattern="/**"         access="IS_AUTHENTICATED_ANONYMOUSLY" requires-channel="any" />

  <security:form-login login-page="/login.html" default-target-url="/admin/index.html"
                       authentication-failure-url="/login.html?status=error" />
  <security:logout logout-url="/logout.html" invalidate-session="true" logout-success-url="/show.jobs.html"/>
  <security:session-management>
     <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="false"/>
  </security:session-management>
  <security:custom-filter ref="openIDFilter"                   position="OPENID_FILTER" />
</security:http>

<bean id="openIDFilter" class="org.jrecruiter.web.security.RegistrationAwareOpenIDAuthenticationFilter">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="consumer" ref="attributeAwareOpenIDConsumer"/>
  <property name="authenticationSuccessHandler"        ref="openIDFilterSuccess"/>
  <property name="authenticationFailureHandler"        ref="openIDFilterFailure"/>
  <property name="registrationTargetUrlRequestHandler" ref="openIDFilterRedirectToRegistration"/>
</bean>

<bean id="openIDFilterRedirectToRegistration" class="org.jrecruiter.web.security.RegistrationTargetUrlRequestHandler">
  <property name="defaultTargetUrl" value="/registration/signup.html"/>
</bean>
<bean id="openIDFilterSuccess" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
  <property name="defaultTargetUrl" value="/admin/index.html"/>
</bean>
 
<bean id="openIDFilterFailure" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
  <property name="defaultFailureUrl" value="/login.html?status=error"/>
</bean>

<bean id="attributeAwareOpenIDProvider" class="org.jrecruiter.web.security.AttributeAwareOpenIDProvider" scope="prototype">
  <constructor-arg ref="userService"/>
</bean>

<bean id="attributeAwareOpenIDConsumer" class="org.jrecruiter.web.security.AttributeAwareOpenIDConsumer"/>


I did some customization: public class AttributeAwareOpenIDConsumer extends OpenID4JavaConsumer {
  public AttributeAwareOpenIDConsumer() throws ConsumerException {
         super(Arrays.asList(UsedOpenIdAttribute.FIRST_NAME.getOpenIdAttribute(),
                                     UsedOpenIdAttribute.LAST_NAME.getOpenIdAttribute(),
                                     UsedOpenIdAttribute.EMAIL.getOpenIdAttribute(),
                                     UsedOpenIdAttribute.AX_FIRST_NAME.getOpenIdAttribute(),
                                     UsedOpenIdAttribute.AX_LAST_NAME.getOpenIdAttribute(),
                                     UsedOpenIdAttribute.NAME_PERSON.getOpenIdAttribute()));
  }
}
I also created a custom class AttributeAwareOpenIDProvider which extends org.springframework.security.openid.OpenIDAuthenticationProvider. It overrides public Authentication authenticate(Authentication authentication) Thus, I can hook into the actual authentication process and inject my own logic.

For example,  if the OpenID authentication succeeds it does not necessarily mean that your account exists, yet. Therefore, if OpenID authentication succeeds (if (status == OpenIDAuthenticationStatus.SUCCESS)), I try loading the user from my application's database (userDetailsService). If then a UsernameNotFoundException is thrown I collect a series of OpenID attributes from the org.springframework.security.openid.OpenIDAuthenticationToken. Once finished, I am throwing a custom AuthenticationSucessButMissingRegistrationException. I use it to redirect to the registration page and pre-populate the registration form with some of the collected OpenID attributes.

I hope this gives you some ideas of how you can integrate OpenID into your SpringSecurity infrastructure. I am myself still in the early learning phase regarding OpenID and I still need to figure out how to best manage multiple authentication realms within my application. But that may be a reason for another blog post.

Labels: , , ,

Friday, January 22, 2010

Remote Profiling of JBoss using VisualVM

I ran into an issue while trying to setup profiling (using VisualVM) of a remote JBoss server instance. It turns out that the default steps I have found on the internet, assume that your target server (Where JBoss is running on) is accessible via the hostname not only by IP address. Well, just in case you live in an environment where you can access your server via IP but not via hostname, this blog post may hopefully save you an hour googling the solution. In order to setup remote profiling I did:

To my run.conf file (JBoss/bin) I added:

JAVA_OPTS="$JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=6789"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=IP_ADDRESS_OF_MY_JBOSS"

Particularly, the last line was very important. Without it I was able to telnet to port 6789, thinking everything is cool, however I was unable to connect to it via VisualVM. This missing line caused a few frustrations.

Anyway, once these lines were added, you need to configure jstatd. I created a policy file (I called it tools.policy) for the JVM containing:

grant {
  permission java.security.AllPermission;
};

Then, I would be able to start up jstatd:

jstatd -p 1099 -J-Djava.security.policy=tools.policy

And finally, I was able to startup JBoss and connect to my server from VisualVM.

Labels: , ,

Thursday, January 14, 2010

Registration Opens for DevNexus 2010

Here is an annoucement that I would like to get out regarding the Atlanta Java Users Group's (AJUG) professional developer conference:

The DevNexus conference will be held in Atlanta March 8–9, 2010 and registration is now open. DevNexus covers a wide range of the most exciting topics related to the Java™ platform.
This year, our sophisticated line-up of speakers covers dynamic programming languages such as Scala and Groovy, as well as Rich Internet Applications (RIA) such as Adobe Flex and Google Web Toolkit (GWT). Furthermore, we have a dedicated track on Google technologies, which not only covers GWT but also Google App Engine and Google Wave. Additionally, DevNexus has sessions covering popular open source projects such as Spring, Maven and HtmlUnit, as well as presentations on software architecture, agile software development methodologies and much more!
Please join us for this exceptional event.
The organizers of DevNexus are focused on making sure the conference provides the best possible educational value by offering attendees a special early bird rate of $150 if they register between now and February 16. Regular admission for the two-day conference is $185, a group discount is also available. The ticket price includes the two-day conference pass as well as meals.
This is the second DevNexus event, which is the continuation of the annual AJUG developer conferences that started in 2004.
For further information: http://www.devnexus.com/

Labels: , , ,

Tuesday, January 12, 2010

DevNexus 2010 Conference Updates

I have spent a few late nights lately, to get the preparations for the Atlanta DevNexus conference into the final stage. The line-up of speakers is getting fuller by the day. I am personally really excited that James Ward (Adobe), Keith Donald (SpringSource) and Lex Spoon (Google) are presenting and we have many, many more presenters covering a ton of material.

I will try my best to update the website (http://www.devnexus.com) with the current list of speakers and presentations, soon.

Which also reminds me to finalize our press-release to announce the conference...I hope to get all that done within the next 2 days. Thus, watch http://www.devnexus.com/ for updates. And please sign-up!
For that price, you won't get a better educational value (...brought to you by your friendly Atlanta Java Users Group)

Labels: , , , ,

Friday, January 1, 2010

Automating User Registrations with OpenID and Spring Security 3.0 - Part 2

This is the continuation of part 1. See also part 3.

Spring Security provides support for OpenID out of the box. It is fairly easy to setup basic OpenID authentication. It even can automatically generate the respective login forms for you. But for my use case I wanted something more elaborate. Here is a basic flow of my "Spring Security OpenID integration solution" (early working draft):

Step 1: User starts the login process using OpenID.
Note that the 'OpenID' between providers varies quite a bit.




Step 2: After pressing the Login button, Spring Security processes the request and using openid4java under the hood, you are redirected to the login page of your OpenID provider in this case Google.

 

Step 3: In step 2 you authenticated successfully (with Google in this case), but you don't have a valid account with jRecruiter itself, yet: In this instance, grab all the useful information that is available through the OpenID account/profile and then forward (Redirect) to the registration page. There pre-fill the form with the grabbed information (E.g. email, first name, last name etc.)


 


Of course I need to add some more sophistication around my user registration process. Nevertheless, I hope the general flow is clear. While OpenID is a fairly widely adopted standard, there seems to be a bit of fluctuation in regards to what data sets providers will allow you to fetch, as well as how to fetch them (e.g. different name-spaces). Thus, it looks like in order to automated an OpenID-supported registration process, you need to be aware (code for) specific providers. I need to explore that area a bit more.

In my next posting I will finally provide some source code. If find some time, take a look and play around with openid4java. The OSS project provides various examples, and the 'simple-openid' example is really helpful for understanding the actual openID registration process. Stay tuned.

Labels: , , ,