<commit_before>// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package com.microsoft.aad.adal;

import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;

import com.microsoft.aad.adal.AuthenticationParameters.AuthenticationParamCallback;
import com.microsoft.aad.adal.Logger.ILogger;
import com.microsoft.aad.adal.Logger.LogLevel;

import junit.framework.Assert;

import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

@RunWith(AndroidJUnit4.class)
public class AuthenticationParamsTests extends AndroidTestHelper {

    protected static final String TAG = "AuthenticationParamsTests";

    @Test
    public void testGetAuthority() {
        AuthenticationParameters param = new AuthenticationParameters();
        assertTrue("authority should be null", param.getAuthority() == null);
    }

    @Test
    public void testGetResource() {
        AuthenticationParameters param = new AuthenticationParameters();
        assertTrue("resource should be null", param.getResource() == null);
    }

    @Test
    public void testCreateFromResourceUrlInvalidFormat() throws IOException, JSONException {
        Logger.d(TAG, "test:" + getClass().getName() + "thread:" + android.os.Process.myTid());

        //mock http response
        final HttpURLConnection mockedConnection = Mockito.mock(HttpURLConnection.class);
        HttpUrlConnectionFactory.setMockedHttpUrlConnection(mockedConnection);
        Util.prepareMockedUrlConnection(mockedConnection);
        Mockito.when(mockedConnection.getOutputStream()).thenReturn(Mockito.mock(OutputStream.class));
        Mockito.when(mockedConnection.getInputStream()).thenReturn(
                Util.createInputStream(Util.getSuccessTokenResponse(false, false)));
        Mockito.when(mockedConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);

        final TestResponse testResponse = new TestResponse();
        setupAsyncParamRequest("http://www.cnn.com", testResponse);

        assertNotNull("Exception null", testResponse.getException());
        assertNull("Parameter is not null", testResponse.getParam());
        assertTrue(
                "Check header exception",
                testResponse.getException().getMessage() == AuthenticationParameters.AUTH_HEADER_WRONG_STATUS);
    }

    @Test
    public void testCreateFromResponseAuthenticateHeader() {
        assertThrowsException(ResourceAuthenticationChallengeException.class,
                AuthenticationParameters.AUTH_HEADER_MISSING.toLowerCase(), new ThrowableRunnable() {

                    @Override
                    public void run() throws ResourceAuthenticationChallengeException {
                        AuthenticationParameters.createFromResponseAuthenticateHeader(null);
                    }
                });

        // empty value inside the authorization_uri will throw exception
        assertThrowsException(ResourceAuthenticationChallengeException.class,
                AuthenticationParameters.AUTH_HEADER_MISSING_AUTHORITY.toLowerCase(), new ThrowableRunnable() {

                    @Override
                    public void run() throws ResourceAuthenticationChallengeException {
                        AuthenticationParameters
                                .createFromResponseAuthenticateHeader("Bearer\t resource=\"is=outer, space=ornot\",\t\t  authorization_uri=\"\"");
                    }
                });
    }

    /**
     * test external service deployed at Azure
     */
    @Test
    public void testCreateFromResourceUrlPositive() throws IOException {
        Logger.d(TAG, "test:" + getClass().getName() + "thread:" + android.os.Process.myTid());

        final HttpURLConnection mockedConnection = Mockito.mock(HttpURLConnection.class);
        HttpUrlConnectionFactory.setMockedHttpUrlConnection(mockedConnection);
        Util.prepareMockedUrlConnection(mockedConnection);

        final String response = "Bearer authorization_uri=\"https://login.windows.net/test.onmicrosoft.com\", resource=\"testresource\"";
        Mockito.when(mockedConnection.getInputStream()).thenReturn(
                Util.createInputStream(response));
        Mockito.when(mockedConnection.getResponseCode()).thenReturn(
                HttpURLConnection.HTTP_UNAUTHORIZED);

        Mockito.when(mockedConnection.getHeaderFields()).thenReturn(Collections.singletonMap(
                AuthenticationParameters.AUTHENTICATE_HEADER, Collections.singletonList(response)));

        final TestResponse testResponse = new TestResponse();
        setupAsyncParamRequest("https://testapi007.azurewebsites.net/api/WorkItem", testResponse);

        assertNull("Exception is not null", testResponse.getException());
        assertNotNull("Check parameter", testResponse.getParam());
        Logger.i(TAG, "test:" + getClass().getName(), "authority:" + testResponse.getParam().getAuthority());
        assertEquals("https://login.windows.net/test.onmicrosoft.com", testResponse.getParam()
                .getAuthority().trim());
    }

    @Test
    public void testParseResponsePositive() throws ClassNotFoundException,
            IllegalArgumentException, IllegalAccessException, InvocationTargetException {

        Method m = getParseResponseMethod();

        verifyAuthenticationParam(
                m,
                "Bearer scope=\"blah=scope, scope=blah\" , authorization_uri=\"https://login.windows.net/tenant\"",
                "https://login.windows.net/tenant", null);

        verifyAuthenticationParam(
                m,
                "Bearer scope=\"is=outer, space=ornot\",\t\t  authorization_uri=\"https://login.windows.net/tenant\"",
                "https://login.windows.net/tenant", null);

        verifyAuthenticationParam(
                m,
                "Bearer\tscope=\"is=outer, space=ornot\",\t\t  authorization_uri=\"https://login.windows.net/tenant\" ,resource_id=\"blah=resource, resource=blah\"",
                "https://login.windows.net/tenant", "blah=resource, resource=blah");

        LogCallback callback = new LogCallback(ADALError.DEVELOPER_BEARER_HEADER_MULTIPLE_ITEMS);
        Logger.getInstance().setExternalLogger(callback);
        verifyAuthenticationParam(
                m,
                "Bearer   \t  scope=\"is=outer, space=ornot\",\t\t  authorization_uri=\"https://login.windows.net/tenant\", authorization_uri=\"https://login.windows.net/tenant\"",
                "https://login.windows.net/tenant", null);

        assertTrue("Has warning for redudant items", callback.isCalled());
        Logger.getInstance().setExternalLogger(null);
    }

    private void verifyAuthenticationParam(Method m, String headerValue, String authorizationUri,<commit_msg>Adding new test where Bearer is not the first challenge<commit_after>// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package com.microsoft.aad.adal;

import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;

import com.microsoft.aad.adal.AuthenticationParameters.AuthenticationParamCallback;
import com.microsoft.aad.adal.Logger.ILogger;
import com.microsoft.aad.adal.Logger.LogLevel;

import junit.framework.Assert;

import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

@RunWith(AndroidJUnit4.class)
public class AuthenticationParamsTests extends AndroidTestHelper {

    protected static final String TAG = "AuthenticationParamsTests";

    @Test
    public void testGetAuthority() {
        AuthenticationParameters param = new AuthenticationParameters();
        assertTrue("authority should be null", param.getAuthority() == null);
    }

    @Test
    public void testGetResource() {
        AuthenticationParameters param = new AuthenticationParameters();
        assertTrue("resource should be null", param.getResource() == null);
    }

    @Test
    public void testCreateFromResourceUrlInvalidFormat() throws IOException, JSONException {
        Logger.d(TAG, "test:" + getClass().getName() + "thread:" + android.os.Process.myTid());

        //mock http response
        final HttpURLConnection mockedConnection = Mockito.mock(HttpURLConnection.class);
        HttpUrlConnectionFactory.setMockedHttpUrlConnection(mockedConnection);
        Util.prepareMockedUrlConnection(mockedConnection);
        Mockito.when(mockedConnection.getOutputStream()).thenReturn(Mockito.mock(OutputStream.class));
        Mockito.when(mockedConnection.getInputStream()).thenReturn(
                Util.createInputStream(Util.getSuccessTokenResponse(false, false)));
        Mockito.when(mockedConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);

        final TestResponse testResponse = new TestResponse();
        setupAsyncParamRequest("http://www.cnn.com", testResponse);

        assertNotNull("Exception null", testResponse.getException());
        assertNull("Parameter is not null", testResponse.getParam());
        assertTrue(
                "Check header exception",
                testResponse.getException().getMessage() == AuthenticationParameters.AUTH_HEADER_WRONG_STATUS);
    }

    @Test
    public void testCreateFromResponseAuthenticateHeader() {
        assertThrowsException(ResourceAuthenticationChallengeException.class,
                AuthenticationParameters.AUTH_HEADER_MISSING.toLowerCase(), new ThrowableRunnable() {

                    @Override
                    public void run() throws ResourceAuthenticationChallengeException {
                        AuthenticationParameters.createFromResponseAuthenticateHeader(null);
                    }
                });

        // empty value inside the authorization_uri will throw exception
        assertThrowsException(ResourceAuthenticationChallengeException.class,
                AuthenticationParameters.AUTH_HEADER_MISSING_AUTHORITY.toLowerCase(), new ThrowableRunnable() {

                    @Override
                    public void run() throws ResourceAuthenticationChallengeException {
                        AuthenticationParameters
                                .createFromResponseAuthenticateHeader("Bearer\t resource=\"is=outer, space=ornot\",\t\t  authorization_uri=\"\"");
                    }
                });
    }

    /**
     * test external service deployed at Azure
     */
    @Test
    public void testCreateFromResourceUrlPositive() throws IOException {
        Logger.d(TAG, "test:" + getClass().getName() + "thread:" + android.os.Process.myTid());

        final HttpURLConnection mockedConnection = Mockito.mock(HttpURLConnection.class);
        HttpUrlConnectionFactory.setMockedHttpUrlConnection(mockedConnection);
        Util.prepareMockedUrlConnection(mockedConnection);

        final String response = "Bearer authorization_uri=\"https://login.windows.net/test.onmicrosoft.com\", resource=\"testresource\"";
        Mockito.when(mockedConnection.getInputStream()).thenReturn(
                Util.createInputStream(response));
        Mockito.when(mockedConnection.getResponseCode()).thenReturn(
                HttpURLConnection.HTTP_UNAUTHORIZED);

        Mockito.when(mockedConnection.getHeaderFields()).thenReturn(Collections.singletonMap(
                AuthenticationParameters.AUTHENTICATE_HEADER, Collections.singletonList(response)));

        final TestResponse testResponse = new TestResponse();
        setupAsyncParamRequest("https://testapi007.azurewebsites.net/api/WorkItem", testResponse);

        assertNull("Exception is not null", testResponse.getException());
        assertNotNull("Check parameter", testResponse.getParam());
        Logger.i(TAG, "test:" + getClass().getName(), "authority:" + testResponse.getParam().getAuthority());
        assertEquals("https://login.windows.net/test.onmicrosoft.com", testResponse.getParam()
                .getAuthority().trim());
    }

    @Test
    public void testParseResponsePositive() throws ClassNotFoundException,
            IllegalArgumentException, IllegalAccessException, InvocationTargetException {

        Method m = getParseResponseMethod();

        verifyAuthenticationParam(
                m,
                "Bearer scope=\"blah=scope, scope=blah\" , authorization_uri=\"https://login.windows.net/tenant\"",
                "https://login.windows.net/tenant", null);

        verifyAuthenticationParam(
                m,
                "Bearer scope=\"is=outer, space=ornot\",\t\t  authorization_uri=\"https://login.windows.net/tenant\"",
                "https://login.windows.net/tenant", null);

        verifyAuthenticationParam(
                m,
                "Bearer\tscope=\"is=outer, space=ornot\",\t\t  authorization_uri=\"https://login.windows.net/tenant\" ,resource_id=\"blah=resource, resource=blah\"",
                "https://login.windows.net/tenant", "blah=resource, resource=blah");

        LogCallback callback = new LogCallback(ADALError.DEVELOPER_BEARER_HEADER_MULTIPLE_ITEMS);
        Logger.getInstance().setExternalLogger(callback);
        verifyAuthenticationParam(
                m,
                "Bearer   \t  scope=\"is=outer, space=ornot\",\t\t  authorization_uri=\"https://login.windows.net/tenant\", authorization_uri=\"https://login.windows.net/tenant\"",
                "https://login.windows.net/tenant", null);

        assertTrue("Has warning for redudant items", callback.isCalled());
        Logger.getInstance().setExternalLogger(null);
    }

    @Test
    public void testSuccessfullyParsesWhenBearerNotFirstClaim()
            throws ClassNotFoundException, InvocationTargetException, IllegalAccessException {
        Method m = getParseResponseMethod();

        verifyAuthenticationParam(
                m,
                "Basic realm=\"https://login.microsoftonline.com/tenant\", Bearer scope=\"blah=scope, scope=blah\" , authorization_uri=\"https://login.windows.net/tenant\"",
                "https://login.windows.net/tenant", null);
    }

    private void verifyAuthenticationParam(Method m, String headerValue, String authorizationUri,
{'fraction_non_alphanumeric': 0.10144764265194615, 'fraction_numerical': 0.0005632850785782684, 'mean_word_length': 3.4032738095238093, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 27, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6990475', 'n_tokens_mistral': 4495, 'n_tokens_neox': 4302, 'n_words': 1015}