导航菜单

页面标题

页面副标题

St.John's v1.0.9 - AzureActiveDirectoryWebViewClient.java 源代码

正在查看: St.John's v1.0.9 应用的 AzureActiveDirectoryWebViewClient.java JAVA 源代码文件

本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。


package com.microsoft.identity.common.internal.ui.webview;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.webkit.ClientCertRequest;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import com.microsoft.identity.common.adal.internal.AuthenticationConstants;
import com.microsoft.identity.common.adal.internal.util.StringExtensions;
import com.microsoft.identity.common.internal.broker.PackageHelper;
import com.microsoft.identity.common.internal.ui.webview.certbasedauth.AbstractCertBasedAuthChallengeHandler;
import com.microsoft.identity.common.internal.ui.webview.certbasedauth.AbstractSmartcardCertBasedAuthChallengeHandler;
import com.microsoft.identity.common.internal.ui.webview.certbasedauth.CertBasedAuthFactory;
import com.microsoft.identity.common.internal.ui.webview.challengehandlers.PKeyAuthChallengeHandler;
import com.microsoft.identity.common.java.AuthenticationConstants;
import com.microsoft.identity.common.java.challengehandlers.PKeyAuthChallengeFactory;
import com.microsoft.identity.common.java.constants.FidoConstants;
import com.microsoft.identity.common.java.exception.ClientException;
import com.microsoft.identity.common.java.exception.ErrorStrings;
import com.microsoft.identity.common.java.providers.RawAuthorizationResult;
import com.microsoft.identity.common.java.ui.webview.authorization.IAuthorizationCompletionCallback;
import com.microsoft.identity.common.java.util.StringUtil;
import com.microsoft.identity.common.logging.Logger;
import java.net.URISyntaxException;
import java.security.Principal;
import java.util.HashMap;
import java.util.Locale;

public class AzureActiveDirectoryWebViewClient extends OAuth2WebViewClient {
    private static final String DEVICE_CERT_ISSUER = "CN=MS-Organization-Access";
    public static final String ERROR = "error";
    public static final String ERROR_DESCRIPTION = "error_description";
    public static final String ERROR_SUBCODE = "error_subcode";
    private static final String TAG = "AzureActiveDirectoryWebViewClient";
    private AbstractCertBasedAuthChallengeHandler mCertBasedAuthChallengeHandler;
    private final CertBasedAuthFactory mCertBasedAuthFactory;
    private final String mRedirectUrl;
    private HashMap<String, String> mRequestHeaders;

    public AzureActiveDirectoryWebViewClient(Activity activity, IAuthorizationCompletionCallback iAuthorizationCompletionCallback, OnPageLoadedCallback onPageLoadedCallback, String str) {
        super(activity, iAuthorizationCompletionCallback, onPageLoadedCallback);
        this.mRedirectUrl = str;
        this.mCertBasedAuthFactory = new CertBasedAuthFactory(activity);
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String str) {
        if (StringUtil.isNullOrEmpty(str)) {
            throw new IllegalArgumentException("Redirect to empty url in web view.");
        }
        return handleUrl(webView, str);
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest webResourceRequest) {
        return handleUrl(webView, webResourceRequest.getUrl().toString());
    }

    public void setRequestHeaders(HashMap<String, String> hashMap) {
        this.mRequestHeaders = hashMap;
    }

    private boolean handleUrl(WebView webView, String str) {
        String str2 = TAG + ":handleUrl";
        String lowerCase = str.toLowerCase(Locale.US);
        try {
            if (isPkeyAuthUrl(lowerCase)) {
                Logger.info(str2, "WebView detected request for pkeyauth challenge.");
                new PKeyAuthChallengeHandler(webView, getCompletionCallback()).processChallenge(new PKeyAuthChallengeFactory().getPKeyAuthChallengeFromWebViewRedirect(str));
                return true;
            }
            if (isRedirectUrl(lowerCase)) {
                Logger.info(str2, "Navigation starts with the redirect uri.");
                processRedirectUrl(webView, str);
                return true;
            }
            if (isWebsiteRequestUrl(lowerCase)) {
                Logger.info(str2, "It is an external website request");
                processWebsiteRequest(webView, str);
                return true;
            }
            if (isInstallRequestUrl(lowerCase)) {
                Logger.info(str2, "It is an install request");
                processInstallRequest(webView, str);
                return true;
            }
            if (isWebCpUrl(lowerCase)) {
                Logger.info(str2, "It is a request from WebCP");
                processWebCpRequest(webView, str);
                return true;
            }
            if (isPlayStoreUrl(lowerCase)) {
                Logger.info(str2, "Request to open PlayStore.");
                return processPlayStoreURL(webView, str);
            }
            if (isAuthAppMFAUrl(lowerCase)) {
                Logger.info(str2, "Request to link account with Authenticator.");
                processAuthAppMFAUrl(str);
                return true;
            }
            if (isAmazonAppRedirect(lowerCase)) {
                Logger.info(str2, "It is an Amazon app request");
                processAmazonAppUri(str);
                return true;
            }
            if (isInvalidRedirectUri(str)) {
                Logger.info(str2, "Check for Redirect Uri.");
                processInvalidRedirectUri(webView, str);
                return true;
            }
            if (isBlankPageRequest(lowerCase)) {
                Logger.info(str2, "It is an blank page request");
                return true;
            }
            if (!isUriSSLProtected(lowerCase)) {
                Logger.info(str2, "Check for SSL protection");
                processSSLProtectionCheck(webView, str);
                return true;
            }
            if (isHeaderForwardingRequiredUri(str)) {
                processHeaderForwardingRequiredUri(webView, str);
                return true;
            }
            Logger.info(str2, "This maybe a valid URI, but no special handling for this mentioned URI, hence deferring to WebView for loading.");
            processInvalidUrl(str);
            return false;
        } catch (ClientException e) {
            Logger.error(str2, e.getErrorCode(), null);
            Logger.errorPII(str2, e.getMessage(), e);
            returnError(e.getErrorCode(), e.getMessage());
            webView.stopLoading();
            return true;
        }
    }

    private boolean isUriSSLProtected(String str) {
        return str.startsWith(AuthenticationConstants.Broker.REDIRECT_SSL_PREFIX);
    }

    private boolean isBlankPageRequest(String str) {
        return "about:blank".equals(str);
    }

    private boolean isInvalidRedirectUri(String str) {
        return isBrokerRequest(getActivity().getIntent()) && str.startsWith("msauth");
    }

    private boolean isAuthAppMFAUrl(String str) {
        return str.startsWith(AuthenticationConstants.Broker.AUTHENTICATOR_MFA_LINKING_PREFIX);
    }

    private boolean isPlayStoreUrl(String str) {
        return str.startsWith(AuthenticationConstants.Broker.PLAY_STORE_INSTALL_PREFIX);
    }

    private boolean isPkeyAuthUrl(String str) {
        return str.startsWith(AuthenticationConstants.Broker.PKEYAUTH_REDIRECT.toLowerCase(Locale.ROOT));
    }

    private boolean isPasskeyUrl(String str) {
        return str.startsWith(FidoConstants.PASSKEY_PROTOCOL_REDIRECT.toLowerCase(Locale.ROOT));
    }

    private boolean isRedirectUrl(String str) {
        return str.startsWith(this.mRedirectUrl.toLowerCase(Locale.US));
    }

    private boolean isWebsiteRequestUrl(String str) {
        return str.startsWith(AuthenticationConstants.Broker.BROWSER_EXT_PREFIX);
    }

    private boolean isInstallRequestUrl(String str) {
        return str.startsWith(AuthenticationConstants.Broker.BROWSER_EXT_INSTALL_PREFIX);
    }

    private boolean isBrokerRequest(Intent intent) {
        return (intent == null || StringExtensions.isNullOrBlank(intent.getStringExtra(AuthenticationConstants.Broker.BROKER_REQUEST))) ? false : true;
    }

    private boolean isWebCpUrl(String str) {
        return str.startsWith(AuthenticationConstants.Broker.BROWSER_EXT_WEB_CP);
    }

    private boolean isAmazonAppRedirect(String str) {
        return str.startsWith(AuthenticationConstants.Broker.AMAZON_APP_REDIRECT_PREFIX);
    }

    private boolean isHeaderForwardingRequiredUri(String str) {
        boolean startsWith = str.startsWith("https://login.live.com/");
        HashMap<String, String> hashMap = this.mRequestHeaders;
        return startsWith && (hashMap != null && !hashMap.isEmpty());
    }

    protected void processRedirectUrl(WebView webView, String str) {
        Logger.info(TAG + ":processRedirectUrl", "It is pointing to redirect. Final url can be processed to get the code or error.");
        getCompletionCallback().onChallengeResponseReceived(RawAuthorizationResult.fromRedirectUri(str));
        webView.stopLoading();
    }

    private void processWebsiteRequest(WebView webView, String str) {
        String str2 = TAG + ":processWebsiteRequest";
        webView.stopLoading();
        if (str.contains(AuthenticationConstants.Broker.BROWSER_DEVICE_CA_URL_QUERY_STRING_PARAMETER)) {
            Logger.info(str2, "This is a device CA request.");
            PackageHelper packageHelper = new PackageHelper(getActivity().getPackageManager());
            if (packageHelper.isPackageInstalledAndEnabled(AuthenticationConstants.Broker.IPPHONE_APP_PACKAGE_NAME) && AuthenticationConstants.Broker.IPPHONE_APP_SIGNATURE.equals(packageHelper.getSha1SignatureForPackage(AuthenticationConstants.Broker.IPPHONE_APP_PACKAGE_NAME)) && packageHelper.isPackageInstalledAndEnabled(AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME)) {
                try {
                    launchCompanyPortal();
                    return;
                } catch (Exception unused) {
                    Logger.warn(str2, "Failed to launch Company Portal, falling back to browser.");
                }
            }
            openLinkInBrowser(str);
            returnResult(RawAuthorizationResult.ResultCode.MDM_FLOW);
            return;
        }
        openLinkInBrowser(str);
        returnResult(RawAuthorizationResult.ResultCode.CANCELLED);
    }

    private boolean processPlayStoreURL(WebView webView, String str) {
        String str2 = TAG + ":processPlayStoreURL";
        webView.stopLoading();
        if (!str.startsWith("market://details?id=com.microsoft.windowsintune.companyportal") && !str.startsWith("market://details?id=com.azure.authenticator")) {
            Logger.info(str2, "The URI is either trying to open an unknown application or contains unknown query parameters");
            return false;
        }
        String str3 = AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME;
        if (!str.contains(AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME)) {
            str3 = AuthenticationConstants.Broker.AZURE_AUTHENTICATOR_APP_PACKAGE_NAME;
        }
        Logger.info(str2, "Request to open PlayStore to install package : '" + str3 + "'");
        try {
            Intent intent = new Intent("android.intent.action.VIEW", Uri.parse(AuthenticationConstants.Broker.PLAY_STORE_INSTALL_PREFIX.concat(str3)));
            intent.addFlags(268468224);
            getActivity().startActivity(intent);
            return true;
        } catch (ActivityNotFoundException e) {
            Logger.error(str2, "PlayStore is not present on the device", e);
            return true;
        }
    }

    private void processAuthAppMFAUrl(String str) {
        String str2 = TAG + ":processAuthAppMFAUrl";
        Logger.verbose(str2, "Linking Account in Broker for MFA.");
        try {
            Intent intent = new Intent("android.intent.action.VIEW", Uri.parse(str));
            intent.addFlags(268435456);
            getActivity().startActivity(intent);
        } catch (ActivityNotFoundException e) {
            Logger.error(str2, "Failed to open the Authenticator application.", e);
        }
    }

    private void launchCompanyPortal() {
        Logger.verbose(TAG + ":launchCompanyPortal", "Sending intent to launch the CompanyPortal.");
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(AuthenticationConstants.Broker.COMPANY_PORTAL_APP_PACKAGE_NAME, AuthenticationConstants.Broker.COMPANY_PORTAL_APP_LAUNCH_ACTIVITY_NAME));
        intent.addFlags(268468224);
        getActivity().startActivity(intent);
        returnResult(RawAuthorizationResult.ResultCode.MDM_FLOW);
    }

    private void processAmazonAppUri(String str) {
        String str2 = TAG + ":processAmazonAppUri";
        getActivity().startActivity(new Intent("android.intent.action.VIEW", Uri.parse(str)));
        Logger.info(str2, "Sent Intent to launch Amazon app");
    }

    private void openLinkInBrowser(String str) {
        String str2 = TAG + ":openLinkInBrowser";
        Logger.info(str2, "Try to open url link in browser");
        Intent intent = new Intent("android.intent.action.VIEW", Uri.parse(str.replace(AuthenticationConstants.Broker.BROWSER_EXT_PREFIX, AuthenticationConstants.Broker.REDIRECT_SSL_PREFIX)));
        if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
            getActivity().startActivity(intent);
        } else {
            Logger.warn(str2, "Unable to find an app to resolve the activity.");
        }
    }

    private void processWebCpRequest(WebView webView, String str) {
        webView.stopLoading();
        if (str.equalsIgnoreCase(AuthenticationConstants.Broker.WEBCP_LAUNCH_COMPANY_PORTAL_URL)) {
            launchCompanyPortal();
            return;
        }
        returnError(ErrorStrings.WEBCP_URI_INVALID, "Unexpected URL from WebCP: " + str);
    }

    private void processInstallRequest(final WebView webView, String str) {
        String str2 = TAG + ":processInstallRequest";
        RawAuthorizationResult fromRedirectUri = RawAuthorizationResult.fromRedirectUri(str);
        if (fromRedirectUri.getResultCode() != RawAuthorizationResult.ResultCode.BROKER_INSTALLATION_TRIGGERED) {
            getCompletionCallback().onChallengeResponseReceived(fromRedirectUri);
            webView.stopLoading();
            return;
        }
        final String str3 = StringExtensions.getUrlParameters(str).get(AuthenticationConstants.AAD.APP_LINK_KEY);
        Logger.info(str2, "Launching the link to app:" + str3);
        getCompletionCallback().onChallengeResponseReceived(fromRedirectUri);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                AzureActiveDirectoryWebViewClient.this.getActivity().startActivity(new Intent("android.intent.action.VIEW", Uri.parse(str3.replace(AuthenticationConstants.Broker.BROWSER_EXT_PREFIX, AuthenticationConstants.Broker.REDIRECT_SSL_PREFIX))));
                webView.stopLoading();
            }
        }, 1000L);
        webView.stopLoading();
    }

    private void processInvalidRedirectUri(WebView webView, String str) {
        String str2 = TAG + ":processInvalidRedirectUri";
        Logger.error(str2, "The RedirectUri is not as expected.", null);
        Logger.errorPII(str2, String.format("Received %s and expected %s", str, this.mRedirectUrl), null);
        returnError(ErrorStrings.DEVELOPER_REDIRECTURI_INVALID, String.format("The RedirectUri is not as expected. Received %s and expected %s", str, this.mRedirectUrl));
        webView.stopLoading();
    }

    private void processSSLProtectionCheck(WebView webView, String str) {
        Logger.error(TAG + ":processSSLProtectionCheck", "The webView was redirected to an unsafe URL: " + removeQueryParametersOrRedact(str), null);
        returnError(ErrorStrings.WEBVIEW_REDIRECTURL_NOT_SSL_PROTECTED, "The webView was redirected to an unsafe URL.");
        webView.stopLoading();
    }

    private void processInvalidUrl(String str) {
        Logger.infoPII(TAG + ":processInvalidUrl", "We are declining to override loading and redirect to invalid URL: '" + removeQueryParametersOrRedact(str) + "' the user's url pattern is '" + this.mRedirectUrl + "'");
    }

    private void processHeaderForwardingRequiredUri(WebView webView, String str) {
        Logger.infoPII(TAG + ":processHeaderForwardingRequiredUri", "We are loading this new URL: '" + removeQueryParametersOrRedact(str) + "' with original requestHeaders appended.");
        webView.loadUrl(str, this.mRequestHeaders);
    }

    private String removeQueryParametersOrRedact(String str) {
        String str2 = TAG + ":removeQueryParametersOrRedact";
        try {
            return StringExtensions.removeQueryParameterFromUrl(str);
        } catch (URISyntaxException e) {
            Logger.errorPII(str2, "Redirect URI has invalid syntax, unable to parse", e);
            return "redacted";
        }
    }

    private void returnResult(RawAuthorizationResult.ResultCode resultCode) {
        getCompletionCallback().onChallengeResponseReceived(RawAuthorizationResult.fromResultCode(resultCode));
    }

    private void returnError(String str, String str2) {
        getCompletionCallback().onChallengeResponseReceived(RawAuthorizationResult.fromException(new ClientException(str, str2)));
    }

    @Override
    public void onReceivedClientCertRequest(WebView webView, final ClientCertRequest clientCertRequest) {
        String str = TAG + ":onReceivedClientCertRequest";
        Principal[] principals = clientCertRequest.getPrincipals();
        if (principals != null) {
            for (Principal principal : principals) {
                if (principal.getName().contains(DEVICE_CERT_ISSUER)) {
                    Logger.info(str, "Cancelling the TLS request, not responding to TLS challenge triggered by device authentication.");
                    clientCertRequest.cancel();
                    return;
                }
            }
        }
        AbstractCertBasedAuthChallengeHandler abstractCertBasedAuthChallengeHandler = this.mCertBasedAuthChallengeHandler;
        if (abstractCertBasedAuthChallengeHandler != null) {
            abstractCertBasedAuthChallengeHandler.cleanUp();
        }
        this.mCertBasedAuthFactory.createCertBasedAuthChallengeHandler(new CertBasedAuthFactory.CertBasedAuthChallengeHandlerCallback() {
            @Override
            public void onReceived(AbstractCertBasedAuthChallengeHandler abstractCertBasedAuthChallengeHandler2) {
                AzureActiveDirectoryWebViewClient.this.mCertBasedAuthChallengeHandler = abstractCertBasedAuthChallengeHandler2;
                if (AzureActiveDirectoryWebViewClient.this.mCertBasedAuthChallengeHandler != null) {
                    AzureActiveDirectoryWebViewClient.this.mCertBasedAuthChallengeHandler.processChallenge(clientCertRequest);
                } else {
                    clientCertRequest.cancel();
                }
            }
        });
    }

    public void onDestroy() {
        AbstractCertBasedAuthChallengeHandler abstractCertBasedAuthChallengeHandler = this.mCertBasedAuthChallengeHandler;
        if (abstractCertBasedAuthChallengeHandler != null) {
            abstractCertBasedAuthChallengeHandler.cleanUp();
        }
        this.mCertBasedAuthFactory.onDestroy();
    }

    public void finalizeBeforeSendingResult(RawAuthorizationResult rawAuthorizationResult, ISendResultCallback iSendResultCallback) {
        AbstractCertBasedAuthChallengeHandler abstractCertBasedAuthChallengeHandler = this.mCertBasedAuthChallengeHandler;
        if (abstractCertBasedAuthChallengeHandler == null) {
            iSendResultCallback.onResultReady();
            return;
        }
        abstractCertBasedAuthChallengeHandler.emitTelemetryForCertBasedAuthResults(rawAuthorizationResult);
        AbstractCertBasedAuthChallengeHandler abstractCertBasedAuthChallengeHandler2 = this.mCertBasedAuthChallengeHandler;
        if (!(abstractCertBasedAuthChallengeHandler2 instanceof AbstractSmartcardCertBasedAuthChallengeHandler)) {
            iSendResultCallback.onResultReady();
        } else {
            ((AbstractSmartcardCertBasedAuthChallengeHandler) abstractCertBasedAuthChallengeHandler2).promptSmartcardRemovalForResult(iSendResultCallback);
        }
    }
}