Search in sources :

Example 1 with ChallengeResponse

use of com.microsoft.aad.adal.ChallengeResponseBuilder.ChallengeResponse in project azure-activedirectory-library-for-android by AzureAD.

the class Oauth2 method postMessage.

private AuthenticationResult postMessage(String requestMessage, Map<String, String> headers) throws IOException, AuthenticationException {
    final String methodName = ":postMessage";
    AuthenticationResult result = null;
    final HttpEvent httpEvent = startHttpEvent();
    final URL authority = StringExtensions.getUrl(getTokenEndpoint());
    if (authority == null) {
        stopHttpEvent(httpEvent);
        throw new AuthenticationException(ADALError.DEVELOPER_AUTHORITY_IS_NOT_VALID_URL);
    }
    httpEvent.setHttpPath(authority);
    try {
        mWebRequestHandler.setRequestCorrelationId(mRequest.getCorrelationId());
        mWebRequestHandler.setClientVersion(AuthenticationContext.getVersionName());
        ClientMetrics.INSTANCE.beginClientMetricsRecord(authority, mRequest.getCorrelationId(), headers);
        HttpWebResponse response = mWebRequestHandler.sendPost(authority, headers, requestMessage.getBytes(AuthenticationConstants.ENCODING_UTF8), "application/x-www-form-urlencoded");
        httpEvent.setResponseCode(response.getStatusCode());
        httpEvent.setCorrelationId(mRequest.getCorrelationId().toString());
        stopHttpEvent(httpEvent);
        if (response.getStatusCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
            if (response.getResponseHeaders() != null && response.getResponseHeaders().containsKey(AuthenticationConstants.Broker.CHALLENGE_REQUEST_HEADER)) {
                // Device certificate challenge will send challenge request
                // in 401 header.
                String challengeHeader = response.getResponseHeaders().get(AuthenticationConstants.Broker.CHALLENGE_REQUEST_HEADER).get(0);
                Logger.i(TAG + methodName, "Device certificate challenge request. ", "Challenge header: " + challengeHeader);
                if (!StringExtensions.isNullOrBlank(challengeHeader)) {
                    // Handle each specific challenge header
                    if (StringExtensions.hasPrefixInHeader(challengeHeader, AuthenticationConstants.Broker.CHALLENGE_RESPONSE_TYPE)) {
                        final HttpEvent challengeHttpEvent = startHttpEvent();
                        challengeHttpEvent.setHttpPath(authority);
                        Logger.v(TAG + methodName, "Received pkeyAuth device challenge.");
                        ChallengeResponseBuilder certHandler = new ChallengeResponseBuilder(mJWSBuilder);
                        Logger.v(TAG + methodName, "Processing device challenge.");
                        final ChallengeResponse challengeResponse = certHandler.getChallengeResponseFromHeader(challengeHeader, authority.toString());
                        headers.put(AuthenticationConstants.Broker.CHALLENGE_RESPONSE_HEADER, challengeResponse.getAuthorizationHeaderValue());
                        Logger.v(TAG + methodName, "Sending request with challenge response.");
                        response = mWebRequestHandler.sendPost(authority, headers, requestMessage.getBytes(AuthenticationConstants.ENCODING_UTF8), "application/x-www-form-urlencoded");
                        challengeHttpEvent.setResponseCode(response.getStatusCode());
                        challengeHttpEvent.setCorrelationId(mRequest.getCorrelationId().toString());
                        stopHttpEvent(challengeHttpEvent);
                    }
                } else {
                    throw new AuthenticationException(ADALError.DEVICE_CERTIFICATE_REQUEST_INVALID, "Challenge header is empty", response);
                }
            } else {
                // AAD server returns 401 response for wrong request
                // messages
                Logger.v(TAG + methodName, "401 http status code is returned without authorization header.");
            }
        }
        boolean isBodyEmpty = TextUtils.isEmpty(response.getBody());
        if (!isBodyEmpty) {
            // Protocol related errors will read the error stream and report
            // the error and error description
            Logger.v(TAG + methodName, "Token request does not have exception.");
            try {
                result = processTokenResponse(response, httpEvent);
            } catch (final ServerRespondingWithRetryableException e) {
                result = retry(requestMessage, headers);
                if (result != null) {
                    return result;
                }
                if (mRequest.getIsExtendedLifetimeEnabled()) {
                    Logger.v(TAG + methodName, "WebResponse is not a success due to: " + response.getStatusCode());
                    throw e;
                } else {
                    Logger.v(TAG + methodName, "WebResponse is not a success due to: " + response.getStatusCode());
                    throw new AuthenticationException(ADALError.SERVER_ERROR, "WebResponse is not a success due to: " + response.getStatusCode(), response);
                }
            }
            ClientMetrics.INSTANCE.setLastError(null);
        }
        if (result == null) {
            // non-protocol related error
            String errMessage = isBodyEmpty ? "Status code:" + response.getStatusCode() : response.getBody();
            Logger.e(TAG + methodName, ADALError.SERVER_ERROR.getDescription(), errMessage, ADALError.SERVER_ERROR);
            throw new AuthenticationException(ADALError.SERVER_ERROR, errMessage, response);
        } else {
            ClientMetrics.INSTANCE.setLastErrorCodes(result.getErrorCodes());
        }
    } catch (final UnsupportedEncodingException e) {
        ClientMetrics.INSTANCE.setLastError(null);
        Logger.e(TAG + methodName, ADALError.ENCODING_IS_NOT_SUPPORTED.getDescription(), e.getMessage(), ADALError.ENCODING_IS_NOT_SUPPORTED, e);
        throw e;
    } catch (final SocketTimeoutException e) {
        result = retry(requestMessage, headers);
        if (result != null) {
            return result;
        }
        ClientMetrics.INSTANCE.setLastError(null);
        if (mRequest.getIsExtendedLifetimeEnabled()) {
            Logger.e(TAG + methodName, ADALError.SERVER_ERROR.getDescription(), e.getMessage(), ADALError.SERVER_ERROR, e);
            throw new ServerRespondingWithRetryableException(e.getMessage(), e);
        } else {
            Logger.e(TAG + methodName, ADALError.SERVER_ERROR.getDescription(), e.getMessage(), ADALError.SERVER_ERROR, e);
            throw e;
        }
    } catch (final IOException e) {
        ClientMetrics.INSTANCE.setLastError(null);
        Logger.e(TAG + methodName, ADALError.SERVER_ERROR.getDescription(), e.getMessage(), ADALError.SERVER_ERROR, e);
        throw e;
    } finally {
        ClientMetrics.INSTANCE.endClientMetricsRecord(ClientMetricsEndpointType.TOKEN, mRequest.getCorrelationId());
    }
    return result;
}
Also used : UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) URL(java.net.URL) HttpWebResponse(com.microsoft.identity.common.adal.internal.net.HttpWebResponse) ChallengeResponse(com.microsoft.aad.adal.ChallengeResponseBuilder.ChallengeResponse) SocketTimeoutException(java.net.SocketTimeoutException)

Example 2 with ChallengeResponse

use of com.microsoft.aad.adal.ChallengeResponseBuilder.ChallengeResponse in project azure-activedirectory-library-for-android by AzureAD.

the class WebviewHelper method getPreKeyAuthInfo.

/**
 * @param challengeUrl URL from which challenge response is received
 * @return PreKeyAuth class filled in
 * @throws UnsupportedEncodingException on malformed exception
 * @throws AuthenticationException      on parameter validation failure
 */
public PreKeyAuthInfo getPreKeyAuthInfo(String challengeUrl) throws UnsupportedEncodingException, AuthenticationException {
    JWSBuilder jwsBuilder = new JWSBuilder();
    ChallengeResponseBuilder certHandler = new ChallengeResponseBuilder(jwsBuilder);
    final ChallengeResponse challengeResponse = certHandler.getChallengeResponseFromUri(challengeUrl);
    final HashMap<String, String> headers = new HashMap<String, String>();
    headers.put(AuthenticationConstants.Broker.CHALLENGE_RESPONSE_HEADER, challengeResponse.getAuthorizationHeaderValue());
    String loadUrl = challengeResponse.getSubmitUrl();
    HashMap<String, String> parameters = StringExtensions.getUrlParameters(challengeResponse.getSubmitUrl());
    Logger.i(TAG, "Get submit url. ", "SubmitUrl:" + challengeResponse.getSubmitUrl());
    if (!parameters.containsKey(AuthenticationConstants.OAuth2.CLIENT_ID)) {
        loadUrl = loadUrl + "?" + mOauth.getAuthorizationEndpointQueryParameters();
    }
    return new PreKeyAuthInfo(headers, loadUrl);
}
Also used : HashMap(java.util.HashMap) JWSBuilder(com.microsoft.identity.common.adal.internal.JWSBuilder) ChallengeResponse(com.microsoft.aad.adal.ChallengeResponseBuilder.ChallengeResponse)

Example 3 with ChallengeResponse

use of com.microsoft.aad.adal.ChallengeResponseBuilder.ChallengeResponse in project azure-activedirectory-library-for-android by AzureAD.

the class BasicWebViewClient method shouldOverrideUrlLoading.

@Override
public // loaded in the current WebView.
boolean shouldOverrideUrlLoading(final WebView view, final String url) {
    final String methodName = ":shouldOverrideUrlLoading";
    com.microsoft.identity.common.internal.logging.Logger.verbose(TAG + methodName, "Navigation is detected.");
    if (url.startsWith(PKEYAUTH_REDIRECT)) {
        com.microsoft.identity.common.internal.logging.Logger.verbose(TAG + methodName, "Webview detected request for pkeyauth challenge.");
        view.stopLoading();
        setPKeyAuthStatus(true);
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    final ChallengeResponseBuilder certHandler = new ChallengeResponseBuilder(new JWSBuilder());
                    final ChallengeResponse challengeResponse = certHandler.getChallengeResponseFromUri(url);
                    final Map<String, String> headers = new HashMap<>();
                    headers.put(CHALLENGE_RESPONSE_HEADER, challengeResponse.getAuthorizationHeaderValue());
                    postRunnable(new Runnable() {

                        @Override
                        public void run() {
                            String loadUrl = challengeResponse.getSubmitUrl();
                            com.microsoft.identity.common.internal.logging.Logger.verbose(TAG + methodName, "Respond to pkeyAuth challenge.");
                            com.microsoft.identity.common.internal.logging.Logger.verbosePII(TAG + methodName, "Challenge submit url:" + challengeResponse.getSubmitUrl());
                            view.loadUrl(loadUrl, headers);
                        }
                    });
                } catch (final AuthenticationServerProtocolException e) {
                    com.microsoft.identity.common.internal.logging.Logger.errorPII(TAG + methodName, "Argument exception", e);
                    // It should return error code and finish the
                    // activity, so that onActivityResult implementation
                    // returns errors to callback.
                    final Intent resultIntent = new Intent();
                    resultIntent.putExtra(RESPONSE_AUTHENTICATION_EXCEPTION, e);
                    if (mRequest != null) {
                        resultIntent.putExtra(RESPONSE_REQUEST_INFO, mRequest);
                    }
                    sendResponse(BROWSER_CODE_AUTHENTICATION_EXCEPTION, resultIntent);
                } catch (final AuthenticationException e) {
                    com.microsoft.identity.common.internal.logging.Logger.error(TAG + methodName, "Failed to create device certificate response", null);
                    com.microsoft.identity.common.internal.logging.Logger.errorPII(TAG + methodName, "Error", e);
                    // It should return error code and finish the
                    // activity, so that onActivityResult implementation
                    // returns errors to callback.
                    final Intent resultIntent = new Intent();
                    resultIntent.putExtra(RESPONSE_AUTHENTICATION_EXCEPTION, e);
                    if (mRequest != null) {
                        resultIntent.putExtra(RESPONSE_REQUEST_INFO, mRequest);
                    }
                    sendResponse(BROWSER_CODE_AUTHENTICATION_EXCEPTION, resultIntent);
                }
            }
        }).start();
        return true;
    } else if (url.toLowerCase(Locale.US).startsWith(mRedirect.toLowerCase(Locale.US))) {
        com.microsoft.identity.common.internal.logging.Logger.verbose(TAG + methodName, "Navigation starts with the redirect uri.");
        Intent errorIntent = parseError(url);
        if (errorIntent != null) {
            // Catch WEB-UI cancel request
            com.microsoft.identity.common.internal.logging.Logger.info(TAG + methodName, "Sending intent to cancel authentication activity");
            view.stopLoading();
            cancelWebViewRequest(errorIntent);
            return true;
        }
        processRedirectUrl(view, url);
        return true;
    } else if (url.startsWith(BROWSER_EXT_PREFIX)) {
        com.microsoft.identity.common.internal.logging.Logger.verbose(TAG + methodName, "It is an external website request");
        view.stopLoading();
        if (url.contains(AuthenticationConstants.Broker.BROWSER_DEVICE_CA_URL_QUERY_STRING_PARAMETER)) {
            Logger.warn(TAG + methodName, "Failed to launch Company Portal, falling back to browser.");
            openLinkInBrowser(url);
            sendResponse(AuthenticationConstants.UIResponse.BROWSER_CODE_MDM, new Intent());
        } else {
            openLinkInBrowser(url);
            cancelWebViewRequest(null);
        }
        return true;
    } else if (url.startsWith(BROWSER_EXT_INSTALL_PREFIX)) {
        com.microsoft.identity.common.internal.logging.Logger.verbose(TAG + methodName, "It is an install request");
        final HashMap<String, String> parameters = StringExtensions.getUrlParameters(url);
        prepareForBrokerResumeRequest();
        // Having thread sleep for 1 second for calling activity to receive the result from
        // prepareForBrokerResumeRequest, thus the receiver for listening broker result return
        // can be registered. openLinkInBrowser will launch activity for going to
        // playstore and broker app download page which brought the calling activity down
        // in the activity stack.
        final int threadSleepForCallingActivity = 1000;
        try {
            Thread.sleep(threadSleepForCallingActivity);
        } catch (InterruptedException e) {
            com.microsoft.identity.common.internal.logging.Logger.warn(TAG + methodName, "Error occurred when having thread sleeping for 1 second.");
        }
        openLinkInBrowser(parameters.get(INSTALL_URL_KEY));
        view.stopLoading();
        return true;
    }
    return processInvalidUrl(view, url);
}
Also used : HashMap(java.util.HashMap) Intent(android.content.Intent) JWSBuilder(com.microsoft.identity.common.adal.internal.JWSBuilder) ChallengeResponse(com.microsoft.aad.adal.ChallengeResponseBuilder.ChallengeResponse)

Aggregations

ChallengeResponse (com.microsoft.aad.adal.ChallengeResponseBuilder.ChallengeResponse)3 JWSBuilder (com.microsoft.identity.common.adal.internal.JWSBuilder)2 HashMap (java.util.HashMap)2 Intent (android.content.Intent)1 HttpWebResponse (com.microsoft.identity.common.adal.internal.net.HttpWebResponse)1 IOException (java.io.IOException)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 SocketTimeoutException (java.net.SocketTimeoutException)1 URL (java.net.URL)1