/*
DConnectLocalOAuth.java
Copyright (c) 2014 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.manager;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import org.deviceconnect.profile.AuthorizationProfileConstants;
import org.deviceconnect.profile.AvailabilityProfileConstants;
import org.deviceconnect.profile.SystemProfileConstants;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;
/**
* デバイスプラグインとのLocal OAuthの認可を行うためのクラス.
* @author NTT DOCOMO, INC.
*/
public class DConnectLocalOAuth {
/** DBのファイル名を定義. */
private static final String DATABASE_NAME = "local_oauth_deviceplugin.db";
/** DBのバージョンを定義. */
private static final int DATABASE_VERSION = 4;
/** OAuthデータ用のテーブル名を定義. */
private static final String OAUTH_DATA_TABLE_NAME = "oauth_data_tbl";
/** アクセストークン用のテーブル名を定義. */
private static final String ACCESS_TOKEN_TABLE_NAME = "access_token_tbl";
/**
* DeviceConnectアプリからアクセストークン無しでアクセス可能なプロファイル名一覧を定義.
*/
public static final String[] IGNORE_PROFILES = {
AuthorizationProfileConstants.PROFILE_NAME,
AvailabilityProfileConstants.PROFILE_NAME,
};
/**
* DeviceConnectManagerからアクセストークン無しでアクセス可能なプロファイル名一覧を定義.
*/
public static final String[] IGNORE_PLUGIN_PROFILES = {
AuthorizationProfileConstants.PROFILE_NAME,
AvailabilityProfileConstants.PROFILE_NAME,
SystemProfileConstants.PROFILE_NAME,
};
/** ロガー. */
private final Logger mLogger = Logger.getLogger("dconnect.manager");
/** DBアクセスヘルパークラス. */
private LocalOAuthSQLiteOpenHelper mDBHelper;
/**
* コンテキスト.
*/
private Context mContext;
/**
* コンストラクタ.
* @param context コンテキスト
*/
public DConnectLocalOAuth(final Context context) {
mContext = context;
mDBHelper = new LocalOAuthSQLiteOpenHelper(context, DATABASE_NAME);
}
/**
* コンストラクタ.
* @param context コンテキスト
* @param filename ファイル名
*/
public DConnectLocalOAuth(final Context context, final String filename) {
mContext = context;
mDBHelper = new LocalOAuthSQLiteOpenHelper(context, filename);
}
/**
* Local OAuthを無視するプロファイルをチェックする.
* @param profileName プロファイル名
* @return 無視する場合はtrue、それ以外はfalse
*/
public boolean checkProfile(final String profileName) {
return Arrays.asList(IGNORE_PROFILES).contains(profileName);
}
/**
* コンテキストを取得する.
* @return コンテキスト
*/
public Context getContext() {
return mContext;
}
/**
* Local OAuthデータを追加する.
* @param origin リクエスト元のオリジン
* @param serviceId サービスID
* @param clientId クライアントID
*/
public synchronized void setOAuthData(final String origin, final String serviceId, final String clientId) {
mLogger.fine("setOAuthData[origin: " + origin + ", serviceId: " + serviceId + ", clinetId: "
+ clientId + "]");
ContentValues values = new ContentValues();
values.put(OAuthDataColumns.ORIGIN, origin);
values.put(OAuthDataColumns.SERVICE_ID, serviceId);
values.put(OAuthDataColumns.CLIENT_ID, clientId);
SQLiteDatabase db = mDBHelper.getWritableDatabase();
try {
db.insertOrThrow(OAUTH_DATA_TABLE_NAME, null, values);
} finally {
db.close();
}
}
/**
* 指定されたサービスIDのLocal OAuthデータを取得する.
* 指定されたサービスIDに対応するデータが存在しない場合はnullを返却する.
* @param origin リクエスト元のオリジン
* @param serviceId サービスID
* @return Local OAuthデータ
*/
public synchronized OAuthData getOAuthData(final String origin, final String serviceId) {
String select = OAuthDataColumns.ORIGIN + "=? and " + OAuthDataColumns.SERVICE_ID + "=?";
String[] selectArgs = {origin, serviceId};
OAuthData client = null;
SQLiteDatabase db = mDBHelper.getReadableDatabase();
Cursor cs = db.query(OAUTH_DATA_TABLE_NAME, null, select, selectArgs, null, null, null);
try {
if (cs.moveToFirst()) {
client = getOAuthData(cs);
}
} finally {
cs.close();
db.close();
}
return client;
}
/**
* 指定されたサービスIDのLocal OAuthのデータを削除する.
* @param origin リクエスト元のオリジン
* @param serviceId サービスID
* @return 削除に成功した場合はtrue、それ以外はfalse
*/
public boolean deleteOAuthData(final String origin, final String serviceId) {
OAuthData oauth = getOAuthData(origin, serviceId);
if (oauth == null) {
return false;
}
return deleteOAuthData(oauth);
}
/**
* 指定されたOAuthのデータをDBから削除する.
* @param oauth LocalOAuthデータ
* @return 削除に成功した場合はtrue、それ以外はfalse
*/
private synchronized boolean deleteOAuthData(final OAuthData oauth) {
if (oauth == null) {
throw new IllegalArgumentException("oauth is null.");
}
mLogger.fine("deleteOAuthData[serviceId: " + oauth.getServiceId()
+ ", clientId: " + oauth.getClientId() + "]");
boolean result = deleteAccessToken(oauth.getId());
SQLiteDatabase db = mDBHelper.getWritableDatabase();
try {
String select = OAuthDataColumns._ID + "=" + oauth.getId();
result = db.delete(OAUTH_DATA_TABLE_NAME, select, null) > 0;
} finally {
db.close();
}
return result;
}
/**
* 指定されたプラグインIDを含むserviceIdを持つLocal OAuthデータをすべて削除する.
* @param pluginId プラグインID
* @return 削除に成功した場合はtrue、それ以外はfalse
*/
public boolean deleteOAuthDatas(final String pluginId) {
List<OAuthData> datas = getOAuthDatas(pluginId);
for (OAuthData auth : datas) {
deleteOAuthData(auth);
}
return true;
}
/**
* 指定されたプラグインIDを含むserviceIdを持つLocal OAuthデータ一覧を取得する.
* 見つからない場合には、サイズが0のリストを返却する。
* @param pluginId プラグインID
* @return LocalOAuthデータ一覧
*/
public synchronized List<OAuthData> getOAuthDatas(final String pluginId) {
List<OAuthData> datas = new ArrayList<OAuthData>();
String select = OAuthDataColumns.SERVICE_ID + " LIKE ?";
String[] selectArgs = {"%" + pluginId + "%"};
SQLiteDatabase db = mDBHelper.getReadableDatabase();
Cursor cs = db.query(OAUTH_DATA_TABLE_NAME, null, select, selectArgs, null, null, null);
try {
if (cs.moveToFirst()) {
do {
OAuthData client = new OAuthData();
client.mId = cs.getInt(cs.getColumnIndex(OAuthDataColumns._ID));
client.mServiceId = cs.getString(cs.getColumnIndex(OAuthDataColumns.SERVICE_ID));
client.mClientId = cs.getString(cs.getColumnIndex(OAuthDataColumns.CLIENT_ID));
client.mOrigin = cs.getString(cs.getColumnIndex(OAuthDataColumns.ORIGIN));
datas.add(client);
} while (cs.moveToNext());
}
} finally {
cs.close();
db.close();
}
return datas;
}
/**
* アクセストークンを削除します.
* @param oauthId OAuthDataを識別するID
* @return 削除に成功した場合はtrue、それ以外はfalse
*/
public synchronized boolean deleteAccessToken(final int oauthId) {
mLogger.fine("deleteAccessToken[oauthId]: " + oauthId);
SQLiteDatabase db = mDBHelper.getWritableDatabase();
try {
String select = AccessTokenColumns.OAUTH_ID + "=" + oauthId + "";
return db.delete(ACCESS_TOKEN_TABLE_NAME, select, null) > 0;
} finally {
db.close();
}
}
/**
* 指定されたアクセストークンを削除する.
*
* @param token アクセストークン
* @return 削除に成功した場合はtrue、それ以外はfalse
*/
public synchronized boolean deleteAccessToken(final String token) {
SQLiteDatabase db = mDBHelper.getWritableDatabase();
try {
String select = AccessTokenColumns.ACCESS_TOKEN + "=?";
String[] selectArgs = {token};
return db.delete(ACCESS_TOKEN_TABLE_NAME, select, selectArgs) > 0;
} finally {
db.close();
}
}
/**
* サービスIDに対応したアクセストークンを取得する.
*
* アクセストークンが見つからない場合にはnullを返却する.
*
* @param oauthId サービスID
* @return アクセストークン
*/
public synchronized String getAccessToken(final int oauthId) {
String select = AccessTokenColumns.OAUTH_ID + "=" + oauthId;
SQLiteDatabase db = mDBHelper.getReadableDatabase();
Cursor cs = db.query(ACCESS_TOKEN_TABLE_NAME, null, select, null, null, null, null);
try {
if (cs.moveToFirst()) {
return cs.getString(cs.getColumnIndex(AccessTokenColumns.ACCESS_TOKEN));
}
} finally {
cs.close();
db.close();
}
return null;
}
/**
* アクセストークンを設定する.
* @param oauthId サービスID
* @param accessToken アクセストークン
*/
public synchronized void setAccessToken(final int oauthId, final String accessToken) {
String select = AccessTokenColumns.OAUTH_ID + "=" + oauthId + "";
ContentValues values = new ContentValues();
values.put(AccessTokenColumns.OAUTH_ID, oauthId);
values.put(AccessTokenColumns.ACCESS_TOKEN, accessToken);
SQLiteDatabase db = mDBHelper.getReadableDatabase();
Cursor cs = db.query(ACCESS_TOKEN_TABLE_NAME, null, select, null, null, null, null);
try {
if (cs.moveToFirst()) {
mDBHelper.getWritableDatabase().update(ACCESS_TOKEN_TABLE_NAME, values, select, null);
} else {
mDBHelper.getWritableDatabase().insertOrThrow(ACCESS_TOKEN_TABLE_NAME, null, values);
}
} finally {
cs.close();
db.close();
}
}
/**
* 保存しているLocal OAuthのデータ一覧を取得する.
* @return Local OAuthのデータ一覧
*/
public synchronized List<OAuthData> getOAuthDataList() {
List<OAuthData> clients = new ArrayList<OAuthData>();
SQLiteDatabase db = mDBHelper.getReadableDatabase();
Cursor cs = db.query(OAUTH_DATA_TABLE_NAME, null, null, null, null, null, null);
try {
if (cs.moveToFirst()) {
do {
clients.add(getOAuthData(cs));
} while (cs.moveToNext());
}
} finally {
cs.close();
db.close();
}
return clients;
}
/**
* DBからOAuthDataを作成する.
* @param cs DBのカーソル
* @return OAuthDataのインスタンス
*/
private OAuthData getOAuthData(final Cursor cs) {
OAuthData cd = new OAuthData();
cd.mId = cs.getInt(cs.getColumnIndex(OAuthDataColumns._ID));
cd.mServiceId = cs.getString(cs.getColumnIndex(OAuthDataColumns.SERVICE_ID));
cd.mClientId = cs.getString(cs.getColumnIndex(OAuthDataColumns.CLIENT_ID));
cd.mOrigin = cs.getString(cs.getColumnIndex(OAuthDataColumns.ORIGIN));
return cd;
}
/**
* LocalOAuth用のデータ.
* @author NTT DOCOMO, INC.
*/
public class OAuthData {
/** 識別子. */
private int mId;
/** リクエスト元のオリジン. */
private String mOrigin;
/** クライアントID. */
private String mClientId;
/** サービスID. */
private String mServiceId;
/**
* 識別子を取得する.
* @return 識別子
*/
public int getId() {
return mId;
}
/**
* 識別子を設定する.
* @param id 識別子
*/
public void setId(final int id) {
this.mId = id;
}
/**
* クライアントIDを取得する.
* @return クライアントID
*/
public String getClientId() {
return mClientId;
}
/**
* クライアントIDを設定する.
* @param clientId クライアントID
*/
public void setClientId(final String clientId) {
this.mClientId = clientId;
}
/**
* リクエスト元のオリジンを取得する.
* @return オリジン
*/
public String getOrigin() {
return mOrigin;
}
/**
* リクエスト元のオリジンを設定する.
* @param origin オリジン
*/
public void setOrigin(final String origin) {
this.mOrigin = origin;
}
/**
* サービスIDを取得する.
* @return サービスID
*/
public String getServiceId() {
return mServiceId;
}
/**
* サービスIDを設定する.
* @param serviceId サービスID
*/
public void setServiceId(final String serviceId) {
this.mServiceId = serviceId;
}
}
/**
* LocalOAuthのデータを保持するDBにアクセスするためのヘルパークラス.
* @author NTT DOCOMO, INC.
*/
private class LocalOAuthSQLiteOpenHelper extends SQLiteOpenHelper {
/**
* コンストラクタ.
* @param context コンテキスト
* @param filename ファイル名
*/
public LocalOAuthSQLiteOpenHelper(final Context context, final String filename) {
super(context, filename, null, DATABASE_VERSION);
}
@Override
public void onCreate(final SQLiteDatabase db) {
createAllTables(db);
}
@Override
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
// 既にテーブルが存在する場合には、削除して、再度テーブルを作成する
db.execSQL("DROP TABLE IF EXISTS " + OAUTH_DATA_TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + ACCESS_TOKEN_TABLE_NAME);
createAllTables(db);
}
/**
* 必要なテーブルをすべて作成する.
* @param db データベース
*/
private void createAllTables(final SQLiteDatabase db) {
createOAuthDataTable(db);
createAccessTokenTable(db);
}
/**
* OAuthデータ用のテーブルを作成する.
* @param db DBアクセス用クラス
*/
private void createOAuthDataTable(final SQLiteDatabase db) {
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE " + OAUTH_DATA_TABLE_NAME);
sql.append("(_id INTEGER PRIMARY KEY, ");
sql.append(OAuthDataColumns.ORIGIN + " TEXT NOT NULL,");
sql.append(OAuthDataColumns.SERVICE_ID + " TEXT NOT NULL,");
sql.append(OAuthDataColumns.CLIENT_ID + " TEXT NOT NULL");
sql.append(");");
db.execSQL(sql.toString());
}
/**
* アクセストークンデータ用のテーブルを作成する.
* @param db DBアクセス用クラス
*/
private void createAccessTokenTable(final SQLiteDatabase db) {
StringBuilder sql = new StringBuilder();
sql.append("CREATE TABLE " + ACCESS_TOKEN_TABLE_NAME + " (");
sql.append(AccessTokenColumns.OAUTH_ID + " INTEGER,");
sql.append(AccessTokenColumns.ACCESS_TOKEN + " TEXT NOT NULL");
sql.append(");");
db.execSQL(sql.toString());
}
}
/**
* カラム名を定義するためのクラス.
* @author NTT DOCOMO, INC.
*/
private static final class OAuthDataColumns implements BaseColumns {
/**
* コンストラクタ.
* インスタンスは作成させないのでprivate.
*/
private OAuthDataColumns() {
}
/**
* クライアントID.
*/
public static final String CLIENT_ID = "client_id";
/**
* サービスID.
*/
public static final String SERVICE_ID = "service_id";
/**
* リクエスト元のオリジン.
*/
public static final String ORIGIN = "origin";
}
/**
* アクセストークン用データカラム名.
* @author NTT DOCOMO, INC.
*/
private static final class AccessTokenColumns implements BaseColumns {
/**
* コンストラクタ.
* インスタンスは作成させないのでprivate.
*/
private AccessTokenColumns() {
}
/**
* OAuthDataのID.
*/
public static final String OAUTH_ID = "oauth_id";
/**
* アクセストークン.
*/
public static final String ACCESS_TOKEN = "access_token";
}
}