package com.seafile.seadroid2.account.ui; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.http.SslCertificate; import android.net.http.SslError; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.view.animation.AnimationUtils; import android.webkit.CookieManager; import android.webkit.SslErrorHandler; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.LinearLayout; import com.seafile.seadroid2.R; import com.seafile.seadroid2.SeadroidApplication; import com.seafile.seadroid2.account.Account; import com.seafile.seadroid2.ssl.CertsManager; import com.seafile.seadroid2.ui.activity.BaseActivity; import com.seafile.seadroid2.ui.dialog.SslConfirmDialog; import com.seafile.seadroid2.util.Utils; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URLEncoder; import java.security.cert.X509Certificate; /** * Shibboleth Authorize page * use cookie to get authorized data * <p/> */ public class ShibbolethAuthorizeActivity extends BaseActivity implements Toolbar.OnMenuItemClickListener { public static final String DEBUG_TAG = "ShibbolethAuthorizeActivity"; public static final String SEAHUB_SHIB_COOKIE_NAME = "seahub_auth"; private WebView mWebview; private LinearLayout mloadingAnimation; public String serverUrl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.shibboleth_authorize_layout); mWebview = (WebView) findViewById(R.id.shibboleth_authorize_wv); mloadingAnimation = (LinearLayout) findViewById(R.id.shibboleth_loading_ll); mWebview.getSettings().setLoadsImagesAutomatically(true); mWebview.getSettings().setJavaScriptEnabled(true); mWebview.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); CustomWebviewClient client = new CustomWebviewClient(); mWebview.setWebViewClient(client); Toolbar toolbar = getActionBarToolbar(); setSupportActionBar(toolbar); toolbar.setOnMenuItemClickListener(this); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setTitle(R.string.shib_actionbar_title); String url = getIntent().getStringExtra(ShibbolethActivity.SHIBBOLETH_SERVER_URL); CookieManager.getInstance().removeAllCookie(); openAuthorizePage(url); } @SuppressLint("LongLogTag") private void openAuthorizePage(String url) { Log.d(DEBUG_TAG, "server url is " + url); serverUrl = url; if (!Utils.isNetworkOn()) { showShortToast(this, getString(R.string.network_down)); return; } String deviceId = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID); String appVersion = ""; Context context = SeadroidApplication.getAppContext(); try { PackageInfo pInfo = context.getPackageManager(). getPackageInfo(context.getPackageName(), 0); appVersion = pInfo.versionName; } catch (PackageManager.NameNotFoundException e) { // ignore } if (!url.endsWith("/")) { url += "/shib-login"; } else url += "shib-login"; try { url += String.format("?shib_platform_version=%s&shib_device_name=%s&shib_platform=%s&shib_device_id=%s&shib_client_version=%s", URLEncoder.encode(Build.VERSION.RELEASE, "UTF-8"), URLEncoder.encode(Build.MODEL, "UTF-8"), "android", URLEncoder.encode(deviceId, "UTF-8"), appVersion); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } Log.d(DEBUG_TAG, "url " + url); mWebview.loadUrl(url); showPageLoading(true); } private void showPageLoading(boolean pageLoading) { if (!pageLoading) { mloadingAnimation.startAnimation(AnimationUtils.loadAnimation( this, android.R.anim.fade_out)); mWebview.startAnimation(AnimationUtils.loadAnimation( this, android.R.anim.fade_in)); mloadingAnimation.setVisibility(View.GONE); mWebview.setVisibility(View.VISIBLE); } else { mloadingAnimation.startAnimation(AnimationUtils.loadAnimation( this, android.R.anim.fade_in)); mWebview.startAnimation(AnimationUtils.loadAnimation( this, android.R.anim.fade_out)); mloadingAnimation.setVisibility(View.VISIBLE); mWebview.setVisibility(View.INVISIBLE); } } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { finish(); return true; } return super.onOptionsItemSelected(item); } @Override public boolean onMenuItemClick(MenuItem item) { return true; } private void displaySSLError() { showPageLoading(false); showShortToast(this, R.string.ssl_error); } class CustomWebviewClient extends WebViewClient { @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { // Display error messages showShortToast(ShibbolethAuthorizeActivity.this, String.format((R.string.shib_load_page_error) + description)); showPageLoading(false); } @SuppressLint("LongLogTag") @Override public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) { Log.d(DEBUG_TAG, "onReceivedSslError " + error.getCertificate().toString()); final Account account = new Account(serverUrl, null, null, false); SslCertificate sslCert = error.getCertificate(); X509Certificate savedCert = CertsManager.instance().getCertificate(account); if (Utils.isSameCert(sslCert, savedCert)) { Log.d(DEBUG_TAG, "trust this cert"); handler.proceed(); } else { Log.d(DEBUG_TAG, "cert is not trusted"); SslConfirmDialog dialog = new SslConfirmDialog(account, Utils.getX509CertFromSslCertHack(sslCert), new SslConfirmDialog.Listener() { @Override public void onAccepted(boolean rememberChoice) { CertsManager.instance().saveCertForAccount(account, rememberChoice); // Ignore SSL certificate validate handler.proceed(); } @Override public void onRejected() { displaySSLError(); handler.cancel(); } }); dialog.show(getSupportFragmentManager(), SslConfirmDialog.FRAGMENT_TAG); } return; } @SuppressLint("LongLogTag") @Override public void onPageFinished(WebView webView, String url) { Log.d(DEBUG_TAG, "onPageFinished " + serverUrl); showPageLoading(false); String cookie = getCookie(serverUrl, SEAHUB_SHIB_COOKIE_NAME); if (cookie == null) return; Account account = null; try { account = parseAccount(Utils.cleanServerURL(serverUrl), cookie); } catch (MalformedURLException e) { Log.e(DEBUG_TAG, e.getMessage()); } returnAccount(account); } } private void returnAccount(Account account) { if (account == null) { return; } Intent retData = new Intent(); retData.putExtras(getIntent()); retData.putExtra(android.accounts.AccountManager.KEY_ACCOUNT_NAME, account.getSignature()); retData.putExtra(android.accounts.AccountManager.KEY_AUTHTOKEN, account.getToken()); retData.putExtra(android.accounts.AccountManager.KEY_ACCOUNT_TYPE, getIntent().getStringExtra(SeafileAuthenticatorActivity.ARG_ACCOUNT_TYPE)); retData.putExtra(SeafileAuthenticatorActivity.ARG_EMAIL, account.getEmail()); retData.putExtra(SeafileAuthenticatorActivity.ARG_SHIB, account.isShib()); retData.putExtra(SeafileAuthenticatorActivity.ARG_SERVER_URI, account.getServer()); // pass auth result back to the ShibbolethActivity setResult(RESULT_OK, retData); finish(); } /** * The cookie value is like seahub_shib="foo@test.com@bd8cc1138", where * foo@test.com is username and bd8cc1138 is api token" */ @SuppressLint("LongLogTag") private Account parseAccount(String url, String cookie) { if (url == null || cookie.isEmpty()) return null; if (cookie.startsWith("\"")) { cookie = cookie.substring(1, cookie.length() - 1); } String email = cookie.substring(0, cookie.lastIndexOf("@")); String token = cookie.substring(cookie.lastIndexOf("@") + 1); if (email.isEmpty() || token.isEmpty()) return null; Log.d(DEBUG_TAG, "email: " + email); Log.d(DEBUG_TAG, "token: " + token); return new Account(url, email, token, true); } @SuppressLint("LongLogTag") public String getCookie(String url, String key) { String CookieValue = ""; CookieManager.getInstance().setAcceptCookie(true); CookieManager cookieManager = CookieManager.getInstance(); String cookies = cookieManager.getCookie(url); if (cookies == null) return null; Log.d(DEBUG_TAG, "All the cookies in a string:" + cookies); String[] allCookies = cookies.split(";"); for (String cookie : allCookies) { if (cookie.contains(key)) { String[] pair = cookie.split("="); CookieValue = pair[1]; } } return CookieValue; } }