Android Open Source - ghwatch Authentication Manager






From Project

Back to project page ghwatch.

License

The source code is released under:

Apache License

If you think the Android project ghwatch listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2014 contributors as indicated by the @authors tag.
 * //from  w  ww  . j  a v a  2s .  c  o m
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.daskiworks.ghwatch.backend;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.net.NoRouteToHostException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.auth.AuthenticationException;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.util.Log;

import com.daskiworks.ghwatch.ActivityTracker;
import com.daskiworks.ghwatch.Utils;
import com.daskiworks.ghwatch.backend.RemoteSystemClient.Response;
import com.daskiworks.ghwatch.model.AccountType;
import com.daskiworks.ghwatch.model.BaseViewData;
import com.daskiworks.ghwatch.model.GHCredentials;
import com.daskiworks.ghwatch.model.GHUserInfo;
import com.daskiworks.ghwatch.model.GHUserLoginInfo;
import com.daskiworks.ghwatch.model.LoadingStatus;

/**
 * Authentication manager class.
 * 
 * @author Vlastimil Elias <vlastimil.elias@worldonline.cz>
 */
public class AuthenticationManager {

  private static final String TAG = "AuthenticationManager";

  private static String client_s;
  private static String client_i;

  static {
    InputStream in = GHConstants.class.getResourceAsStream("clients.properties");
    try {
      Properties props = new Properties();
      if (in != null)
        props.load(in);
      else
        Log.e(TAG, "clients.properties file not found to get Github API keys from");
      client_s = props.getProperty("clients");
      client_i = props.getProperty("clienti");
    } catch (IOException e) {
      Log.e(TAG, "Unable to load secrets for github authentication " + e.getMessage());
    } finally {
      if (in != null)
        try {
          in.close();
        } catch (IOException e) {
          // OK
        }
    }

  }

  private static final String GH_AUTH_REQ_URL = GHConstants.URL_BASE + "/authorizations/clients/" + client_i;
  private static final String GH_USER_REQ_URL = GHConstants.URL_BASE + "/user";

  /**
   * Reload from server is forced automatically if data in persistent store are older than this timeout [millis]
   */
  private static final long USER_INFO_RELOAD_AFTER = Utils.MILLIS_DAY;

  private static final String culiFileName = "cui.td";
  private static final String cuFileName = "cu.td";

  private static final String GH_AUTH_REQ_CONTENT = "{\"client_secret\":\"" + client_s
      + "\",\"scopes\":[\"notifications\",\"repo\"],\"note\":\"GH:watch android app\" }";

  private File culiFile;
  private File cuFile;

  private GHUserInfo currentUserInfo;
  private ExecutorService userInfoExecutorService = Executors.newFixedThreadPool(1);
  private UserInfoLoaderTask userInfoLoaderTask;

  private GHCredentials credentials;

  private static AuthenticationManager instance = null;

  /**
   * Get instance of manager for use.
   * 
   * @param context
   * @return
   */
  public static AuthenticationManager getInstance() {
    if (instance == null) {
      instance = new AuthenticationManager();
    }
    return instance;
  }

  private File getCuliFile(Context context) {
    if (culiFile == null)
      culiFile = context.getFileStreamPath(culiFileName);
    return culiFile;
  }

  private File getCuFile(Context context) {
    if (cuFile == null)
      cuFile = context.getFileStreamPath(cuFileName);
    return cuFile;
  }

  private AuthenticationManager() {
    super();
  }

  /**
   * Get info about current user logged in this application.
   * 
   * @return current user or null if not logged in yet.
   */
  public GHUserLoginInfo loadCurrentUser(Context context) {
    return Utils.readFromStore(TAG, context, getCuliFile(context));
  }

  public static class LoginViewData extends BaseViewData {
    public boolean isOtp;
    public String otpType;
  }

  /**
   * Login user for this application.
   * 
   * @param username for user
   * @param password for user to login
   * @param otp one time password for 2fact authentication
   * @return info about login success
   * 
   */
  public LoginViewData login(Context context, String username, String password, String otp) {
    LoginViewData nswd = new LoginViewData();
    String trackLabel = "OK";
    try {
      String token = remoteLogin(context, new GHCredentials(username, password), otp);
      Log.d(TAG, "Login token: " + token);
      GHUserLoginInfo ui = new GHUserLoginInfo(AccountType.LOCAL, username, token);
      storeCurrentUserLogin(context, ui);
    } catch (OTPAuthenticationException e) {
      nswd.loadingStatus = LoadingStatus.AUTH_ERROR;
      nswd.isOtp = true;
      nswd.otpType = e.getOtpType();
      Log.d(TAG, "Login failed due OTP required: " + e.getMessage());
      trackLabel = "OTP_REQUESTED";
    } catch (InvalidObjectException e) {
      nswd.loadingStatus = LoadingStatus.DATA_ERROR;
      Log.w(TAG, "Login failed due data format problem: " + e.getMessage(), e);
      trackLabel = "ERR_DATA";
    } catch (NoRouteToHostException e) {
      nswd.loadingStatus = LoadingStatus.CONN_UNAVAILABLE;
      trackLabel = "ERR_CONN_NOT_AVAILABLE";
    } catch (AuthenticationException e) {
      nswd.loadingStatus = LoadingStatus.AUTH_ERROR;
      Log.d(TAG, "Login failed due authentication problem: " + e.getMessage());
      trackLabel = "ERR_AUTH";
    } catch (IOException e) {
      nswd.loadingStatus = LoadingStatus.CONN_ERROR;
      Log.w(TAG, "Login failed due connection problem: " + e.getMessage());
      trackLabel = "ERR_CONN";
    } catch (JSONException e) {
      nswd.loadingStatus = LoadingStatus.DATA_ERROR;
      Log.w(TAG, "Login failed due data format problem: " + e.getMessage());
      trackLabel = "ERR_DATA";
    } catch (Exception e) {
      nswd.loadingStatus = LoadingStatus.UNKNOWN_ERROR;
      Log.e(TAG, "Login failed due: " + e.getMessage(), e);
      trackLabel = "ERR_UNKNOWN";
    }
    ActivityTracker.sendEvent(context, ActivityTracker.CAT_BE, "login", trackLabel, 0L);
    return nswd;
  }

  private String remoteLogin(Context context, GHCredentials cred, String otp) throws JSONException, NoRouteToHostException, AuthenticationException,
      ClientProtocolException, URISyntaxException, IOException {
    Map<String, String> headers = null;
    otp = Utils.trimToNull(otp);
    if (otp != null) {
      headers = new HashMap<String, String>();
      headers.put("X-GitHub-OTP", otp);
    }
    Response<String> resp = RemoteSystemClient.putToURL(context, cred, GH_AUTH_REQ_URL, headers, GH_AUTH_REQ_CONTENT);
    JSONObject jo = new JSONObject(resp.data);
    return jo.getString("token");
  }

  private void storeCurrentUserLogin(Context context, GHUserLoginInfo currentUserLoginInfo) {
    Utils.writeToStore(TAG, context, getCuliFile(context), currentUserLoginInfo);
    if (currentUserInfo == null || (currentUserLoginInfo != null && !currentUserLoginInfo.getUsername().equals(currentUserInfo.getUsername()))) {
      currentUserInfo = null;
      Utils.deleteFromStore(context, getCuFile(context));
      loadUserInfoFromServer(context, getGhApiCredentials(context));
    }
    this.credentials = null;
  }

  /**
   * Get credentials of current user for GH API calls.
   * 
   * @return credentials for API calls
   */
  public GHCredentials getGhApiCredentials(Context context) {
    if (credentials != null)
      return credentials;
    GHUserLoginInfo ui = loadCurrentUser(context);
    if (ui != null) {
      credentials = new GHCredentials(ui.getT(), "x-oauth-basic");
      return credentials;
    } else {
      return null;
    }
  }

  /**
   * Get info about currently logged in user. Load it from filesystem so may take longer time, so should be called asynchronously from GUI.
   * 
   * @param context used to load it
   * @return info about current user or null
   */
  public GHUserInfo getCurrentUserInfo(Context context) {
    if (currentUserInfo == null) {
      currentUserInfo = Utils.readFromStore(TAG, context, getCuFile(context));
      if (currentUserInfo == null || currentUserInfo.getUpdateTimestamp() < (System.currentTimeMillis() - USER_INFO_RELOAD_AFTER)) {
        loadUserInfoFromServerAsync(context);
      }
    }
    return currentUserInfo;
  }

  protected void loadUserInfoFromServerAsync(Context context) {
    if (userInfoLoaderTask == null) {
      userInfoLoaderTask = new UserInfoLoaderTask(context, getGhApiCredentials(context));
      userInfoExecutorService.submit(userInfoLoaderTask);
    }
  }

  protected void loadUserInfoFromServer(Context context, GHCredentials ghCredentials) {
    try {
      Response<JSONObject> r = RemoteSystemClient.getJSONObjectFromUrl(context, ghCredentials, GH_USER_REQ_URL, null);
      if (r.data != null) {
        currentUserInfo = new GHUserInfo(r.data);
        Utils.writeToStore(TAG, context, getCuFile(context), currentUserInfo);
      }
    } catch (Throwable th) {
      Log.e(TAG, "User informations loading error: " + th.getMessage(), th);
    }
  }

  private class UserInfoLoaderTask implements Runnable {

    private GHCredentials ghCredentials;
    private Context context;

    UserInfoLoaderTask(Context context, GHCredentials ghCredentials) {
      this.context = context.getApplicationContext();
      this.ghCredentials = ghCredentials;
    }

    @Override
    public void run() {
      try {
        loadUserInfoFromServer(context, ghCredentials);
      } finally {
        userInfoLoaderTask = null;
      }
    }

  }
}




Java Source Code List

com.daskiworks.ghwatch.AboutDialogFragment.java
com.daskiworks.ghwatch.ActivityBase.java
com.daskiworks.ghwatch.ActivityTracker.java
com.daskiworks.ghwatch.FullHeightListView.java
com.daskiworks.ghwatch.IabHelper.java
com.daskiworks.ghwatch.LoginDialogFragment.java
com.daskiworks.ghwatch.MainActivity.java
com.daskiworks.ghwatch.MyBackupAgent.java
com.daskiworks.ghwatch.NotificationListAdapter.java
com.daskiworks.ghwatch.NotificationRepositoriesListAdapter.java
com.daskiworks.ghwatch.SettingsActivity.java
com.daskiworks.ghwatch.StartActivity.java
com.daskiworks.ghwatch.SupportAppDevelopmentDialogFragment.java
com.daskiworks.ghwatch.SwipeDismissListViewTouchListener.java
com.daskiworks.ghwatch.UnreadAppWidgetProvider.java
com.daskiworks.ghwatch.Utils.java
com.daskiworks.ghwatch.WatchedRepositoriesActivity.java
com.daskiworks.ghwatch.WatchedRepositoryListAdapter.java
com.daskiworks.ghwatch.alarm.AlarmBroadcastReceiver.java
com.daskiworks.ghwatch.alarm.MarkNotifiationAsReadReceiver.java
com.daskiworks.ghwatch.backend.AuthenticationManager.java
com.daskiworks.ghwatch.backend.GHConstants.java
com.daskiworks.ghwatch.backend.NotificationStreamParser.java
com.daskiworks.ghwatch.backend.OTPAuthenticationException.java
com.daskiworks.ghwatch.backend.PreferencesUtils.java
com.daskiworks.ghwatch.backend.RemoteSystemClient.java
com.daskiworks.ghwatch.backend.UnreadNotificationsService.java
com.daskiworks.ghwatch.backend.ViewDataReloadStrategy.java
com.daskiworks.ghwatch.backend.WatchedRepositoriesParser.java
com.daskiworks.ghwatch.backend.WatchedRepositoriesService.java
com.daskiworks.ghwatch.image.FileCache.java
com.daskiworks.ghwatch.image.ImageLoader.java
com.daskiworks.ghwatch.image.MemoryCache.java
com.daskiworks.ghwatch.model.AccountType.java
com.daskiworks.ghwatch.model.BaseViewData.java
com.daskiworks.ghwatch.model.BooleanViewData.java
com.daskiworks.ghwatch.model.GHCredentials.java
com.daskiworks.ghwatch.model.GHUserInfo.java
com.daskiworks.ghwatch.model.GHUserLoginInfo.java
com.daskiworks.ghwatch.model.LoadingStatus.java
com.daskiworks.ghwatch.model.NotifCount.java
com.daskiworks.ghwatch.model.NotificationStreamViewData.java
com.daskiworks.ghwatch.model.NotificationStream.java
com.daskiworks.ghwatch.model.Notification.java
com.daskiworks.ghwatch.model.Repository.java
com.daskiworks.ghwatch.model.StringViewData.java
com.daskiworks.ghwatch.model.WatchedRepositoriesViewData.java
com.daskiworks.ghwatch.model.WatchedRepositories.java
com.daskiworks.ghwatch.view.preference.ShowTextPreference.java
com.daskiworks.ghwatch.view.preference.ShowTimestampPreference.java