<commit_before>/*
 * Copyright 2018 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.keycloak.testsuite.admin.client.authorization;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.keycloak.testsuite.utils.io.IOUtil.loadRealm;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.security.cert.X509Certificate;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.undertow.Undertow;
import io.undertow.server.handlers.form.FormData;
import io.undertow.server.handlers.form.FormDataParser;
import io.undertow.server.handlers.form.FormParserFactory;
import org.apache.http.impl.client.HttpClients;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.authorization.ClaimInformationPointProvider;
import org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory;
import org.keycloak.adapters.authorization.PolicyEnforcer;
import org.keycloak.adapters.spi.AuthenticationError;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.HttpFacade.Cookie;
import org.keycloak.adapters.spi.HttpFacade.Request;
import org.keycloak.adapters.spi.HttpFacade.Response;
import org.keycloak.adapters.spi.LogoutError;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.util.JsonSerialization;

/**
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class ClaimInformationPointProviderTest extends AbstractKeycloakTest {

    private static Undertow httpService;

    @BeforeClass
    public static void onBeforeClass() {
        ProfileAssume.assumePreview();
        httpService = Undertow.builder().addHttpListener(8989, "localhost").setHandler(exchange -> {
            if (exchange.isInIoThread()) {
                try {
                    if (exchange.getRelativePath().equals("/post-claim-information-provider")) {
                        FormParserFactory parserFactory = FormParserFactory.builder().build();
                        FormDataParser parser = parserFactory.createParser(exchange);
                        FormData formData = parser.parseBlocking();

                        if (!"Bearer tokenString".equals(exchange.getRequestHeaders().getFirst("Authorization"))
                                || !"post".equalsIgnoreCase(exchange.getRequestMethod().toString())
                                || !"application/x-www-form-urlencoded".equals(exchange.getRequestHeaders().getFirst("Content-Type"))
                                || !exchange.getRequestHeaders().get("header-b").contains("header-b-value1")
                                || !exchange.getRequestHeaders().get("header-b").contains("header-b-value2")
                                || !formData.get("param-a").getFirst().getValue().equals("param-a-value1")
                                || !formData.get("param-a").getLast().getValue().equals("param-a-value2")
                                || !formData.get("param-subject").getFirst().getValue().equals("sub")
                                || !formData.get("param-user-name").getFirst().getValue().equals("username")
                                || !formData.get("param-other-claims").getFirst().getValue().equals("param-other-claims-value1")
                                || !formData.get("param-other-claims").getLast().getValue().equals("param-other-claims-value2")) {
                            exchange.setStatusCode(400);
                            return;
                        }

                        exchange.setStatusCode(200);
                    } else if (exchange.getRelativePath().equals("/get-claim-information-provider")) {
                        if (!"Bearer idTokenString".equals(exchange.getRequestHeaders().getFirst("Authorization"))
                                || !"get".equalsIgnoreCase(exchange.getRequestMethod().toString())
                                || !exchange.getRequestHeaders().get("header-b").contains("header-b-value1")
                                || !exchange.getRequestHeaders().get("header-b").contains("header-b-value2")
                                || !exchange.getQueryParameters().get("param-a").contains("param-a-value1")
                                || !exchange.getQueryParameters().get("param-a").contains("param-a-value2")
                                || !exchange.getQueryParameters().get("param-subject").contains("sub")
                                || !exchange.getQueryParameters().get("param-user-name").contains("username")) {
                            exchange.setStatusCode(400);
                            return;
                        }

                        exchange.setStatusCode(200);
                    } else {
                        exchange.setStatusCode(404);
                    }
                } finally {
                    if (exchange.getStatusCode() == 200) {
                        try {
                            ObjectMapper mapper = JsonSerialization.mapper;
                            JsonParser jsonParser = mapper.getFactory().createParser("{\"a\": \"a-value1\", \"b\": \"b-value1\", \"d\": [\"d-value1\", \"d-value2\"]}");
                            TreeNode treeNode = mapper.readTree(jsonParser);
                            exchange.getResponseSender().send(treeNode.toString());
                        } catch (Exception ignore) {
                            ignore.printStackTrace();
                        }
                    }
                    exchange.endExchange();
                }
            }
        }).build();

        httpService.start();
    }

    @AfterClass
    public static void onAfterClass() {
        httpService.stop();
    }

    @Override
    public void addTestRealms(List<RealmRepresentation> testRealms) {
        RealmRepresentation realm = loadRealm(getClass().getResourceAsStream("/authorization-test/test-authz-realm.json"));
        testRealms.add(realm);
    }

    private ClaimInformationPointProvider getClaimInformationProviderForPath(String path, String providerName) {<commit_msg>KEYCLOAK-8120 Fix NullPointerException in ClaimInformationPointProviderTest<commit_after>/*
 * Copyright 2018 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.keycloak.testsuite.admin.client.authorization;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.keycloak.testsuite.utils.io.IOUtil.loadRealm;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.security.cert.X509Certificate;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.undertow.Undertow;
import io.undertow.server.handlers.form.FormData;
import io.undertow.server.handlers.form.FormDataParser;
import io.undertow.server.handlers.form.FormParserFactory;
import org.apache.http.impl.client.HttpClients;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.authorization.ClaimInformationPointProvider;
import org.keycloak.adapters.authorization.ClaimInformationPointProviderFactory;
import org.keycloak.adapters.authorization.PolicyEnforcer;
import org.keycloak.adapters.spi.AuthenticationError;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.HttpFacade.Cookie;
import org.keycloak.adapters.spi.HttpFacade.Request;
import org.keycloak.adapters.spi.HttpFacade.Response;
import org.keycloak.adapters.spi.LogoutError;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.util.JsonSerialization;

/**
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class ClaimInformationPointProviderTest extends AbstractKeycloakTest {

    private static Undertow httpService;

    @BeforeClass
    public static void onBeforeClass() {
        ProfileAssume.assumePreview();
        httpService = Undertow.builder().addHttpListener(8989, "localhost").setHandler(exchange -> {
            if (exchange.isInIoThread()) {
                try {
                    if (exchange.getRelativePath().equals("/post-claim-information-provider")) {
                        FormParserFactory parserFactory = FormParserFactory.builder().build();
                        FormDataParser parser = parserFactory.createParser(exchange);
                        FormData formData = parser.parseBlocking();

                        if (!"Bearer tokenString".equals(exchange.getRequestHeaders().getFirst("Authorization"))
                                || !"post".equalsIgnoreCase(exchange.getRequestMethod().toString())
                                || !"application/x-www-form-urlencoded".equals(exchange.getRequestHeaders().getFirst("Content-Type"))
                                || !exchange.getRequestHeaders().get("header-b").contains("header-b-value1")
                                || !exchange.getRequestHeaders().get("header-b").contains("header-b-value2")
                                || !formData.get("param-a").getFirst().getValue().equals("param-a-value1")
                                || !formData.get("param-a").getLast().getValue().equals("param-a-value2")
                                || !formData.get("param-subject").getFirst().getValue().equals("sub")
                                || !formData.get("param-user-name").getFirst().getValue().equals("username")
                                || !formData.get("param-other-claims").getFirst().getValue().equals("param-other-claims-value1")
                                || !formData.get("param-other-claims").getLast().getValue().equals("param-other-claims-value2")) {
                            exchange.setStatusCode(400);
                            return;
                        }

                        exchange.setStatusCode(200);
                    } else if (exchange.getRelativePath().equals("/get-claim-information-provider")) {
                        if (!"Bearer idTokenString".equals(exchange.getRequestHeaders().getFirst("Authorization"))
                                || !"get".equalsIgnoreCase(exchange.getRequestMethod().toString())
                                || !exchange.getRequestHeaders().get("header-b").contains("header-b-value1")
                                || !exchange.getRequestHeaders().get("header-b").contains("header-b-value2")
                                || !exchange.getQueryParameters().get("param-a").contains("param-a-value1")
                                || !exchange.getQueryParameters().get("param-a").contains("param-a-value2")
                                || !exchange.getQueryParameters().get("param-subject").contains("sub")
                                || !exchange.getQueryParameters().get("param-user-name").contains("username")) {
                            exchange.setStatusCode(400);
                            return;
                        }

                        exchange.setStatusCode(200);
                    } else {
                        exchange.setStatusCode(404);
                    }
                } finally {
                    if (exchange.getStatusCode() == 200) {
                        try {
                            ObjectMapper mapper = JsonSerialization.mapper;
                            JsonParser jsonParser = mapper.getFactory().createParser("{\"a\": \"a-value1\", \"b\": \"b-value1\", \"d\": [\"d-value1\", \"d-value2\"]}");
                            TreeNode treeNode = mapper.readTree(jsonParser);
                            exchange.getResponseSender().send(treeNode.toString());
                        } catch (Exception ignore) {
                            ignore.printStackTrace();
                        }
                    }
                    exchange.endExchange();
                }
            }
        }).build();

        httpService.start();
    }

    @AfterClass
    public static void onAfterClass() {
        if (httpService != null) {
            httpService.stop();
        }
    }

    @Override
    public void addTestRealms(List<RealmRepresentation> testRealms) {
        RealmRepresentation realm = loadRealm(getClass().getResourceAsStream("/authorization-test/test-authz-realm.json"));
        testRealms.add(realm);
    }

    private ClaimInformationPointProvider getClaimInformationProviderForPath(String path, String providerName) {
{'fraction_non_alphanumeric': 0.11818360784828401, 'fraction_numerical': 0.006430868167202572, 'mean_word_length': 2.454215775158658, 'pattern_counts': {'":': 6, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6006209', 'n_tokens_mistral': 4144, 'n_tokens_neox': 3835, 'n_words': 631}