Monday, August 31, 2015

Using OAuth to connect to Google APIs from a Java desktop application


Google uses OAuth for managing authentication and authorization to its APIs. While the flow of action comes naturally in a Web application, it may be confusing for a Desktop a application. The steps for using OAuth is as follow:

           1. Obtaining OAuth credentials from Google Developpers Console
           2. Request a Token
           3. Use Tokens to Authenticate your Requests
           4. Refresh the token when it expires.

While on a Web application you have the possiblity to use redirect and directly store your token on the current session, in a Desktop application you need enter the URL manually in a browser, retrieve the code, enter it, obtain the token and store it on disk.

Let's go through an example of access to Google Calendar API from a Swing application:

First of all, you need to obtain OAuth Client Credentials from Google Developers Console.

The flow is as follows:
- Use the credentials to request a code from Google OAuth server
- Open a browser and copy the code
- Enter the obtained code in the command line as requested by the application
- Obtain the token and store it on disk
- Use it as long as it is valid, else refresh it

The code below illustrates the process:
 /** Authorizes the installed application to access user's protected data. */
   private static Credential authorize() throws Exception {
    
     // load client secrets
     GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
         new InputStreamReader(GoogleCalendarManager.class.getResourceAsStream("/client_secret_2.json")));
    
     //If the client secrets/Id are not valid
     if (clientSecrets.getDetails().getClientId().startsWith("Enter")
         || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
       System.out.println(
           "Unable to authenticate, Please Enter a Client ID and Secret from https://code.google.com/apis/console/?api=calendar ");
       System.exit(1);
     }
     
     
     GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
         httpTransport, JSON_FACTORY, clientSecrets,
         Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(dataStoreFactory)
         .build();
       
     Credential credential;
     //First Time
     if(flow.getCredentialDataStore().isEmpty()) {
     
   GoogleAuthorizationCodeRequestUrl url =  flow.newAuthorizationUrl();
    url.setRedirectUri("urn:ietf:wg:oauth:2.0:oob");
     System.out.println("Please enter the URL in your browser: " +  url.build().toString());
     System.out.println("Please enter the code: ");
     BufferedReader br = 
                new BufferedReader(new InputStreamReader(System.in));

                String code;
                code = br.readLine();
  
  //System.out.println("received code " + code);
  

  AuthorizationCodeTokenRequest accessTokenRequest = flow.newTokenRequest(code);
  accessTokenRequest.setRedirectUri("urn:ietf:wg:oauth:2.0:oob");
  TokenResponse response = accessTokenRequest.execute();
  
     credential = flow.createAndStoreCredential(response, APPLICATION_NAME);
     }
     //After the first time
     else{
       credential = flow.loadCredential(USER_ID);
      
     }
     
     return credential;
   }



The "client_secret_2.json" is provided by Google OAuth and can be downloaded when the client secrets are set up.

Full example at: https://github.com/zak905/GoogleCalendarAPI


Monday, August 3, 2015

How to secure a Java desktop application using Apache Shiro


Apache Shiro is one of many available Java framework for securing your application. While most of them focus on Web applications, Shiro can be used to secure your Desktop application as well. Shiro focuses on simplicity and can be used even by newbies.

Let's suppose we have users credentials and roles stored in a database, and we want to use Shiro for managing login to the application. Shiro uses the concept of Realm to define the data object that  gives access to user credentials. Since we are accessing user credentials in a database, we will be using JdbcRealm. We need also to define the database queries that will be used to retrieve credentials and roles. Something like: 


//To be adapted to user context
    private static final String AUTHENTICATION_QUERY = "SELECT password FROM users WHERE username=?";
    private static final String ROLES_QUERY = "SELECT access_designation FROM access_level,users WHERE access_level.id=users.access_level_id and users.username = ?" ;


Another important aspect of Shiro is shiro.ini which is used for configuration :
# =============================================================================
 #  Realm configuration
 #
 # =============================================================================
 [main]
 jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
 jdbcRealm.permissionsLookupEnabled = false
 ds = yourpackage.MyDataSource
 jdbcRealm.dataSource=$ds
 securityManager.realms = $jdbcRealm
We need also to define our datasource, which tells Shiro about how to connect to the database.
import com.jolbox.bonecp.BoneCPConfig;
import com.jolbox.bonecp.BoneCPDataSource;

/**
 *
 * @author zakaria
 */
public class MyDataSource extends BoneCPDataSource {
    /** Data source class for retrieving authentication information **/
    public MyDataSource() {
	super();
    /* Change as needed */
	this.setDriverClass("org.sqlite.JDBC");
	this.setJdbcUrl("jdbc:sqlite:mymanagerdb");
	this.setUsername("");
	this.setPassword("");
	this.setDefaultAutoCommit(true);
    }

    /**
     * @param config
     */
    public MyDataSource(BoneCPConfig config) {
	super(config);
    }

}
We are set. We can now define our authentication class:

public class Authenticator {
    
    //To be adapted to user context
    private static final String AUTHENTICATION_QUERY = "SELECT password FROM users WHERE username=?";
    private static final String ROLES_QUERY = "SELECT access_designation FROM access_level,users WHERE access_level.id=users.access_level_id and users.username = ?" ;
    
    /*** Autenticates a user **/
    public Subject authenticate(String username, String pass) {

		Subject currentUser = null;
		try {

	   Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
			// the key "jdbcRealm" must be the same in the shiro.ini file.
JdbcRealm realm = (JdbcRealm) ((IniSecurityManagerFactory) factory).getBeans().get("jdbcRealm");
			realm.setAuthenticationQuery(AUTHENTICATION_QUERY);
			realm.setUserRolesQuery(ROLES_QUERY);
			
			SecurityUtils.setSecurityManager(securityManager);

			currentUser = SecurityUtils.getSubject();

			UsernamePasswordToken token = new UsernamePasswordToken(username, pass);
				
			currentUser.login(token);
				
		} catch (Exception e) {
			e.printStackTrace();
		}
		return currentUser;

	}

}

Finally, we can use our authenticator as needed:

public static void main(String[] args) throws Exception {
		
		String userName = "someUserName";
		String userName = "somePassword";

		Authenticator authenticator = new Authenticator();
        Subject currentUser = authenticator.authenticate(userName, password);
        if(currentUser.isAuthenticated()){
        	Session session = currentUser.getSession();

        	//Storing some attributes
        	session.setAttribute("Connected", "yes");


        	//Retrieving attributes later on 

            String attribute = session.getAttribute("Connected").toString();

            System.out.println("Connected : " + attribute);

        }
        else{
           System.out.println("Could not authenticate user");
        }
		
		

	}
Source code: https://github.com/zak905/ShiroSimpleAuthentication-