Pages

Sunday, June 17, 2012

How to create a simple Maven 2 web project with Eclipse


Here we will have look at how to create a Maven 2 Web application using "Eclipse IDE for Java EE Developers"

If you don't have the IDE, it can be downloaded from here for free.

Maven is a tool that can be used for building and managing any Java-based project. Here we will consider only about how to create a Web Application.

Below are the steps to create the web application,

Step 1: Right click on project explorer and select New-->Other


Step 2: Type "maven" in the text box available, select "Maven 2 Project Creation Wizard", and click "Next"


If you don't have "Maven 2 Project" here, it means you will need to add Maven plugin to eclipse. Find here how to do it:-http://www.dotkam.com/2008/02/24/install-maven-plugin-for-eclipse/

Step 3: Then, in the new window, type an appropriate name for the project and click "Next"


Step 4: In the "Maven Archetypes" type "web" and select "maven-archetype-webapp-RELEASE" from the list, and click next


Step 5: In the "Maven Project Information" window, change the names if you want, else leave it as it is, and then click finish


If you followed the steps correctly, a project will be created in your workspace with the following structure


The pom file will be like below,


Now you can add any dependencies to the POM file and continue with your project. Happy Coding!

Saturday, June 16, 2012

Java-Spring Security Authenticate through Facebook- OAuth 2



Recently I had a requirement of adding "Login with facebook" functionality to my existing spring-java web application. As I was not familiar with this before, tried to find some online examples or tutorials to get some help. But I couldn't find any good tutorial on this and finally had to go through the facebook api and restfb  by myself to find a solution. Since the solution I found is working fine so far, thought to share it hoping it might be useful to someone else too.

My web application was a spring mvc (spring 3) configured and also spring security-3. I had a normal login form to the web app through spring security (/j_spring_security_check). All I wanted was to have a "Login/Connect with Facebook button". My requirement was to authenticate the user in my spring security context after he has been authenticated through Facebook. For this purpose I used a workaround since I couldn't find any other proper solution-even I tried various methods, even Spring social.  In spring social they have specified a very convenient way to interact with Facebook's Graph API once we get the access token from facebook and the access token can be received from Facebook after OAuth authorization. This is exactly where I got stuck. So below is the way I got through it.

I'm going to use server-side authentication with Facebook in this example. 

As the first step, we will have to create an application with Facebook. This application will represent our real application in Facebook, and will give the "App ID/API Key"  and "App Secret" which will be required to connect our application with Facebook.

For this, go to "https://developers.facebook.com/apps" and create a new application by clicking on "Create New App". After entering the required details, you will be given the App Id and App Secret.

Next, according to the Facebook API we have to redirect user to the URL-
"https://www.facebook.com/dialog/oauth?
    client_id=YOUR_APP_ID
   &redirect_uri=YOUR_REDIRECT_URI
   &scope=COMMA_SEPARATED_LIST_OF_PERMISSION_NAMES
   &state=SOME_ARBITRARY_BUT_UNIQUE_STRING"

in order to get the OAuth Dialog from facebook-(the user will enter the Facebook user name and the password here)

What I did was, first redirecting the user to my own controller and redirecting to the above url from my controller-In this way I thought we can get more control over constructing the above url.

So, as the first step, add the something like below in your JSP where the login with Facebook button is required,

<a href="facebookLogin.htm">
<img src="images/fbconnect.png" alt="Connect with Facebook" />
</a>

will appear like :- 
Now the code inside the controller will be like below;

@RequestMapping(value = "/facebookLogin")
public void getFacebookLogin(HttpServletRequest request,HttpServletResponse response) {
String url="https://www.facebook.com/dialog/oauth/?"
 + "client_id=" + ApplicationConstants.FACEBOOK_APP_ID
 + "&redirect_uri=" + ApplicationConstants.FACEBOOK_REDIRECT_URL
 + "&scope=email,publish_stream,user_about_me,friends_about_me"
 + "&state=" + ApplicationConstants.FACEBOOK_EXCHANGE_KEY
 + "&display=page"
 + "&response_type=code";
try {
response.sendRedirect(url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

Lets have a look at the variables appended to the url,

client_id-this is the application id ("App ID/API Key") mentioned above, since this will not change throughout the application, i have put it as a constant in my ApplicationConstants.java interface.
redirect_uri- this will be the url, to which the user will be redirected by Facebook after login/cancellation from the OAuth Dialog. Our next set of code needs to be put here, how to handle the post authentication process. I used like "http://localhost:8080/your_app_name/facebookAuthentication.htm"
scope-The scope parameter allows us to specify a comma separated list of additional permissions which we need the user to grant our application, the complete list can be found here. Add these according to your requirements.
state-this is like a key we used to keep the conversation between our application and Facebook safe, "to ensure the security of the response when the user returns to your app after the authentication step". This can be any string eg:- "justtotestfbresponseafterlogin"-this too is a constant
display- The display mode with which to render the Dialog
response_type-The requested response type, one of code or token, I tried to get the token staright, but I failed, so I'm getting the "code" and using the code we receive, we can get the access token.

Here can be found a complete list of parameters with details to the above URL.

Now its time to see howto handle the response we receive from Facebook when the user redirect to our application from the above URL. this is my code in the controller,

@RequestMapping(value = "/facebookAuthentication", method=RequestMethod.GET)
public String facebookAuthentication(HttpServletRequest request,HttpServletResponse response) {
//Get the parameter "code" from the request
String code=request.getParameter("code");
        //Check if its null or blank or empty
if(StringUtils.isNotEmpty(code)){
 //If we received a valid code, we can continue to the next step
               //Next we want to get the access_token from Facebook using the code we got, 
//use the following url for that, in this url,
//client_id-our app id(same as above), redirect_uri-same as above, client_secret-same as //above, code-the code we just got
String url="https://graph.facebook.com/oauth/access_token?"
                 + "client_id=" + ApplicationConstants.FACEBOOK_APP_ID
                 + "&redirect_uri=" + ApplicationConstants.FACEBOOK_REDIRECT_URL
                 + "&client_secret=" + ApplicationConstants.FACEBOOK_SECRET_KEY
                 + "&code=" + code;
// Create an instance of HttpClient.
        HttpClient client = new HttpClient();
       // Create a method instance.
        GetMethod method = new GetMethod(url);   
       // Provide custom retry handler is necessary
       method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
    new DefaultHttpMethodRetryHandler(3, false));   
       try {
     // Execute the method.
     int statusCode = client.executeMethod(method);
     if (statusCode != HttpStatus.SC_OK) {
       System.err.println("Method failed: " + method.getStatusLine());
     }
     // Read the response body.
     byte[] responseBody = method.getResponseBody();
     // Deal with the response.Use caution: ensure correct character encoding and is
              // not binary data
     String responseBodyString=new String(responseBody);
     //will be like below,                                 //access_token=AAADD1QFhDlwBADrKkn87ZABAz6ZCBQZ//DZD&expires=5178320
    //now get the access_token from the response
     if(responseBodyString.contains("access_token")){
     //success
     String[] mainResponseArray=responseBodyString.split("&");
     //like //{"access_token= AAADD1QFhDlwBADrKkn87ZABAz6ZCBQZ//DZD ","expires=5178320"}
     String accesstoken="";
     for (String string : mainResponseArray) {
if(string.contains("access_token")){
accesstoken=string.replace("access_token=", "").trim();
}
  }
   
     //now we have the access token :)
                 //Great. Now we have the access token, I have used restfb to get the user details here
     FacebookClient facebookClient = new DefaultFacebookClient(accesstoken);
     User user = facebookClient.fetchObject("me", User.class);
                   //In this user object, you will have the details you want from Facebook,  Since we have    the  access token with us, can play around and see what more can be done
//CAME UP TO HERE AND WE KNOW THE USER HAS BEEN AUTHENTICATED BY FACEBOOK, LETS AUTHENTICATE HIM IN OUR APPLICATION
    //NOW I WILL CALL MY doAutoLogin METHOD TO AUTHENTICATE THE USER IN MY SPRING SECURITY CONTEXT
     }else{
     //failed
                   return "redirect:loginPage.htm";
    }     

   } catch (HttpException e) {
     System.err.println("Fatal protocol violation: " + e.getMessage());
     e.printStackTrace();
   } catch (IOException e) {
     System.err.println("Fatal transport error: " + e.getMessage());
     e.printStackTrace();
   } finally {
     // Release the connection.
     method.releaseConnection();
    }
}else{
 //failed
return "redirect:loginPage.htm";
}
}

Now I will show the code i used to authenticate the user in my spring security context,

public String doAutoLogin(String username, String password, HttpServletRequest request)throws Exception {
try {
// Must be called from request filtered by Spring Security,
// otherwise SecurityContextHolder is not updated
  UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
token.setDetails(new WebAuthenticationDetails(request));
Authentication authentication = this.authenticationProvider.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
return ApplicationConstants.SUCCESS;
} catch (Exception e) {
SecurityContextHolder.getContext().setAuthentication(null);
System.out.println("Failure in autoLogin" +  e);
}
return null;
}


Hope this tutorial helps, any feedback is highly appriciated.

In the next tutorial, lets see how to access various information from Facebook and how to publish to Facebook using restfb api and hopefully Spring social too.