/**
* $id$
* Copyright 2011-2012 Renren Inc. All rights reserved.
*/
package com.renren.api.connect.android;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import com.renren.api.connect.android.exception.RenrenAuthError;
import com.renren.api.connect.android.view.RenrenAuthListener;
import com.renren.api.connect.android.view.RenrenWidgetListener;
/**
* @author 李勇(yong.li@opi-corp.com) 2011-6-9
*/
public class SSO {
private static final String LOG_TAG = "SSO";
private Renren renren;
private int mRequestCode;
private RenrenAuthListener mAuthListener;
private RenrenWidgetListener mWidgetDialogListener;
private Activity mActivity;
private String[] authPermissions;
SSO(Renren renren) {
this.renren = renren;
}
/**
* 使用Single Sign-on功能 完成登录和授权(User-Agent Flow)。
* 警告:使用此方法获取返回值请在调用此方法的activity中 重写onActivityResult
* 并在onActivityResult中调用renren.authorizeCallback
*
* @param activity
* @param permissions 应用想拥有的权限列表。
* @param requestCode 在callback时需要的requestCode.
* @param listener
*/
public void authorize(Activity activity, String[] permissions,
final RenrenAuthListener listener, int requestCode) {
mAuthListener = listener;
Intent intent = new Intent();
intent.putExtra("client_id", this.renren.getApiKey());
if (permissions != null && permissions.length > 0) {
intent.putExtra("scope", TextUtils.join(",", permissions));
}
mActivity = activity;
authPermissions = permissions;
mRequestCode = requestCode;
boolean succeed = this.tryRRClientAuth(intent);
if (!succeed) {
this.renren.authorize(activity, permissions, mAuthListener);
}
}
public void authorize(Activity activity, String[] permissions,
final RenrenAuthListener listener, int requestCode, int width, int height) {
mAuthListener = listener;
Intent intent = new Intent();
intent.putExtra("client_id", this.renren.getApiKey());
if (permissions != null && permissions.length > 0) {
intent.putExtra("scope", TextUtils.join(",", permissions));
}
mActivity = activity;
authPermissions = permissions;
mRequestCode = requestCode;
boolean succeed = this.tryRRClientAuth(intent);
if (!succeed) {
this.renren.authorize(activity, permissions, mAuthListener, width, height);
}
}
private boolean tryRRClientAuth(Intent intent) {
boolean didSucceed = true;
intent.setClassName("com.renren.mobile.android",
"com.renren.mobile.android.auth.SSOAuthActivity");
if (!validateAppSignatureForIntent(this.mActivity, intent, RR_APP_SIGNATURE)) {
return false;
}
Log.d(LOG_TAG, "start renren client sso.");
didSucceed = this.startActivity(intent);
Log.d(LOG_TAG, "renren client sso succeed:" + didSucceed);
return didSucceed;
}
/**
* 注意:使用单点登录功能时请务必在调用activity中 重写onActivityResult(int requestCode, int
* resultCode, Intent data)方法 并在该方法中调用authorizeCallback才可以获得返回值。
*/
public void authorizeCallback(int requestCode, int resultCode, Intent data) {
if (requestCode == mRequestCode) {
// Successfully redirected.
if (resultCode == Activity.RESULT_OK) {
// Check OAuth 2.0/2.10 error code.
String error = data.getStringExtra("error");
String error_description = data.getStringExtra("error_description");
if (error != null) {
if (error.equals("service_disabled")) {
Log.d(LOG_TAG, "Hosted auth currently "
+ "disabled. Retrying dialog auth...");
this.renren.authorize(mActivity, authPermissions, mAuthListener);
} else if (error.equals("access_denied")) {
Log.d(LOG_TAG, "Auth canceled by user.");
mAuthListener.onCancelAuth(data.getExtras());
} else {
Log.d(LOG_TAG, "Login failed: " + error);
mAuthListener.onRenrenAuthError(new RenrenAuthError(error,
error_description, null));
}
} else {// No errors.
Log.d(LOG_TAG, "access_token:" + data.getStringExtra("access_token"));
try {
this.renren.updateAccessToken(data.getStringExtra("access_token"));
} catch (RuntimeException e) {
e.printStackTrace();
Log.w(LOG_TAG, e.getMessage());
}
if (this.renren.isSessionKeyValid()) {
mAuthListener.onComplete(data.getExtras());
} else {
mAuthListener.onRenrenAuthError(new RenrenAuthError("unknow",
"Failed to receive access token.", null));
}
}
// An error occurred before we could be redirected.
} else if (resultCode == Activity.RESULT_CANCELED) {
// An Android error occured.
if (data != null) {
Log.d(LOG_TAG, "Login failed: " + data.getStringExtra("error"));
mAuthListener.onRenrenAuthError(new RenrenAuthError(data
.getStringExtra("error"), data.getStringExtra("error_description"),
data.getStringExtra("failing_url")));
} else {// User pressed the 'back' button.
Log.d(LOG_TAG, "Canceled by user.");
Bundle values = new Bundle();
values.putString("error", "press_back");
values.putString("error_description", "User press back key.");
mAuthListener.onCancelAuth(values);
}
}
}
}
public void widgetDialog(Activity activity, Bundle params, final RenrenWidgetListener listener,
String url, int requestCode) {
Intent intent = new Intent();
intent.putExtra("client_id", this.renren.getApiKey());
//widget_dialog_url SSOLib使用
intent.putExtra("widget_dialog_url", url);
this.mWidgetDialogListener = listener;
mActivity = activity;
mRequestCode = requestCode;
intent.putExtras(params);
boolean succee = this.tryRRClientDialog(intent);
if (!succee) {
this.renren.widgetDialog(activity, params, listener, url);
}
}
private boolean tryRRClientDialog(Intent intent) {
intent
.setClassName("com.renren.mobile.android",
"com.renren.mobile.android.auth.SSODialog");
if (!validateAppSignatureForIntent(this.mActivity, intent, RR_APP_SIGNATURE)) {
return false;
}
Log.d(LOG_TAG, "start renren client sso dialog...");
boolean succeed = this.startActivity(intent);
Log.d(LOG_TAG, "renren client sso dialog succeed:" + succeed);
return succeed;
}
public void widgetDialogCallback(int requestCode, int resultCode, Intent data) {
if (requestCode == mRequestCode) {
if (data != null) {
Bundle values = data.getExtras();
String error = values.getString("error");
if (error == null) {
this.mWidgetDialogListener.onComplete(values);
} else if ("access_denied".equals(error)) {
this.mWidgetDialogListener.onCancel(values);
} else {
this.mWidgetDialogListener.onError(values);
}
} else {
Bundle values = new Bundle();
values.putString("error", "press_back");
this.mWidgetDialogListener.onCancel(values);
}
}
}
private boolean validateAppSignatureForIntent(Activity activity, Intent intent,
String targetSignatures) {
ResolveInfo resolveInfo = activity.getPackageManager().resolveActivity(intent, 0);
if (resolveInfo == null) {
Log.i(LOG_TAG, "className:" + intent.getComponent().getClassName());
Log.i(LOG_TAG, "resolveInfo is null!");
return false;
}
String packageName = resolveInfo.activityInfo.packageName;
PackageInfo packageInfo;
try {
packageInfo = activity.getPackageManager().getPackageInfo(packageName,
PackageManager.GET_SIGNATURES);
} catch (NameNotFoundException e) {
Log.w(LOG_TAG, "obtain package info exception:" + e.getMessage());
return false;
}
for (Signature signature : packageInfo.signatures) {
if (signature.toCharsString().equals(targetSignatures)) {
return true;
}
}
return false;
}
private boolean startActivity(Intent intent) {
try {
this.mActivity.startActivityForResult(intent, this.mRequestCode);
return true;
} catch (Exception e) {
e.printStackTrace();
Log.w(LOG_TAG, "start activity " + intent.getComponent().getClassName() + " error "
+ e.getMessage());
}
return false;
}
private static final String RR_APP_SIGNATURE = "3082023e308201a702044b85da7d300d06092"
+ "a864886f70d01010405003065310b300906035504061302434e3110300e0603550408130"
+ "76265696a696e673110300e060355040713076265696a696e67310c300a060355040a130"
+ "36f706931133011060355040b130a72656e72656e2e636f6d310f300d060355040313067"
+ "2656e72656e3020170d3130303232353032303334315a180f323036343131323830323033"
+ "34315a3065310b300906035504061302434e3110300e060355040813076265696a696e67311"
+ "0300e060355040713076265696a696e67310c300a060355040a13036f70693113301106035"
+ "5040b130a72656e72656e2e636f6d310f300d0603550403130672656e72656e30819f300d0"
+ "6092a864886f70d010101050003818d0030818902818100e21721992472cccca98841c6087b"
+ "732b03045240e1ba2f0102888d8346305c2f032cf874feca6a39461026ceaf6cf637b94e76f9d0"
+ "2812236c1d645073ec87cf17e55068c8155acd2c920ba1d192a5731883fcfa382fea62a45c8d77"
+ "90291b085fc7d4e6358a5799b0e752aa10d7560651a705e6909ae49cb4a078c064fcf89502030"
+ "10001300d06092a864886f70d010104050003818100726d02419a0a9b413d0c8af0dec12b0e15"
+ "41b57e8536840e223081f971750d41a493e8968c1f3f32da9e0e85f10e65a0ed11b0e0c61afc51aa"
+ "49c89a5ad549136d960862108aade918726465da15f24e0adf71c84d370d289b349e4ab35262a8"
+ "cbd50e05acd6fbed092c2200e79fa0dc2cfa539ace46525f7772766f3524d0c9";
}