All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.axway.apim.config.GenerateTemplate Maven / Gradle / Ivy

The newest version!
package com.axway.apim.config;

import com.axway.apim.adapter.jackson.CustomYamlFactory;
import com.axway.apim.api.API;
import com.axway.apim.api.model.*;
import com.axway.apim.cli.APIMCLIServiceProvider;
import com.axway.apim.cli.CLIServiceMethod;
import com.axway.apim.config.model.APISecurity;
import com.axway.apim.config.model.GenerateTemplateParameters;
import com.axway.apim.lib.StandardExportParams;
import com.axway.apim.lib.error.AppException;
import com.axway.apim.lib.error.ErrorCode;
import com.axway.apim.lib.utils.URLParser;
import com.axway.apim.lib.utils.Utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.tags.Tag;
import io.swagger.v3.parser.OpenAPIV3Parser;
import io.swagger.v3.parser.core.models.AuthorizationValue;
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.*;

public class GenerateTemplate implements APIMCLIServiceProvider {


    private static final Logger LOG = LoggerFactory.getLogger(GenerateTemplate.class);
    public static final String DEFAULT = "_default";

    @Override
    public String getName() {
        return "Generate Config file template from Open API";
    }

    @Override
    public String getVersion() {
        return GenerateTemplate.class.getPackage().getImplementationVersion();
    }

    @Override
    public String getGroupId() {
        return "template";
    }

    @Override
    public String getGroupDescription() {
        return "Generate APIM CLI Config file template from Open API";
    }

    @CLIServiceMethod(name = "generate", description = "Generate APIM CLI Config file template from Open API")
    public static int generate(String[] args) {
        ObjectMapper objectMapper;
        // Trust all certificate and hostname for openapi parser
        System.setProperty("TRUST_ALL", "true");
        HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);//NOSONAR
        LOG.info("Generating APIM CLI configuration file");
        GenerateTemplateParameters params;
        try {
            params = (GenerateTemplateParameters) GenerateTemplateCLIOptions.create(args).getParams();
        } catch (AppException e) {
            LOG.error("Error", e);
            return e.getError().getCode();
        }
        GenerateTemplate app = new GenerateTemplate();
        try {
            File file = new File(params.getConfig());
            if(file.getParentFile() != null && !file.getParentFile().exists() && (file.getParentFile().mkdirs())){
                    LOG.info("Created new Directory : {}", file.getParentFile());
            }
            APIConfig apiConfig = app.generateTemplate(params);
            try (FileWriter fileWriter = new FileWriter(params.getConfig())) {
                if (params.getOutputFormat().equals(StandardExportParams.OutputFormat.yaml))
                    objectMapper = new ObjectMapper(CustomYamlFactory.createYamlFactory());
                else
                    objectMapper = new ObjectMapper();
                String[] serializeAllExcept = new String[]{"useForInbound", "useForOutbound"};
                FilterProvider filter = new SimpleFilterProvider().setDefaultFilter(SimpleBeanPropertyFilter.serializeAllExcept(serializeAllExcept));
                objectMapper.setFilterProvider(filter);
                objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
                objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
                JsonNode jsonNode = objectMapper.convertValue(apiConfig, JsonNode.class);
                objectMapper.writeValue(fileWriter, jsonNode);
                LOG.info("Writing APIM CLI configuration file to : {}", params.getConfig());
            }
        } catch (AppException e) {
            LOG.error("{} : Error code {}", e.getError().getDescription(), e.getError().getCode());
            return e.getError().getCode();
        }catch (Exception e) {
            LOG.error("Error in processing :", e);
            return 1;
        }
        return 0;
    }


    public APIConfig generateTemplate(GenerateTemplateParameters parameters) throws IOException, CertificateEncodingException, NoSuchAlgorithmException, KeyManagementException {
        List authorizationValues = new ArrayList<>();
        ParseOptions parseOptions = new ParseOptions();
        parseOptions.setResolve(true); // implicit
        String apiDefinition = parameters.getApiDefinition();
        URLParser urlParser = new URLParser(apiDefinition);
        String uri = urlParser.getUri();
        String username = urlParser.getUsername();
        String password = urlParser.getPassword();

        if (username != null && password != null) {
            String credential = Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
            AuthorizationValue authorizationValue = new AuthorizationValue(HttpHeaders.AUTHORIZATION, credential, "header");
            authorizationValues.add(authorizationValue);
        }
        SwaggerParseResult result = new OpenAPIV3Parser().readLocation(uri, authorizationValues, parseOptions);
        List messages = result.getMessages();
        if (!messages.isEmpty()) {
            throw new AppException(messages.toString(), ErrorCode.UNSUPPORTED_API_SPECIFICATION);
        }
        OpenAPI openAPI = result.getOpenAPI();
        Info info = openAPI.getInfo();
        List servers = openAPI.getServers();
        if (servers == null || servers.isEmpty()) {
            throw new AppException("servers element is not found", ErrorCode.UNSUPPORTED_API_SPECIFICATION);
        }
        Server server = servers.get(0);
        String strURL = server.getUrl();
        String basePath;
        String urlString;

        if (strURL.startsWith("http")) {
            URL url = new URL(strURL);
            basePath = url.getPath();
            String protocol = url.getProtocol();
            String host = url.getHost();
            int port = url.getPort();
            if (port == -1) {
                urlString = String.format("%s://%s", protocol, host);
            } else {
                urlString = String.format("%s://%s:%d", protocol, host, port);
            }
        } else {
            basePath = strURL;
            urlString = "https://localhost";
        }
        API api = new API();
        addTags(api, openAPI);
        api.setState("published");
        api.setBackendResourcePath(urlString);
        api.setPath(basePath);
        api.setName(info.getTitle());
        api.setVersion(info.getVersion());
        api.setDescriptionType("original");
        CorsProfile corsProfile = new CorsProfile();
        corsProfile.setName("Custom CORS");
        corsProfile.setIsDefault(false);
        corsProfile.setSupportCredentials(true);
        corsProfile.setOrigins(new String[]{"*"});
        corsProfile.setAllowedHeaders(new String[]{"Authorization", "x-requested-with", "Bearer"});
        corsProfile.setExposedHeaders(new String[]{"Via", "X-CorrelationID"});
        corsProfile.setMaxAgeSeconds("0");

        CorsProfile corsProfileDefault = new CorsProfile();
        corsProfileDefault.setName(DEFAULT);
        corsProfileDefault.setIsDefault(true);
        corsProfileDefault.setOrigins(new String[]{"*"});
        corsProfileDefault.setAllowedHeaders(new String[]{});
        corsProfileDefault.setExposedHeaders(new String[]{"X-CorrelationID"});
        corsProfileDefault.setMaxAgeSeconds("0");

        List corsProfiles = new ArrayList<>();
        corsProfiles.add(corsProfileDefault);
        corsProfiles.add(corsProfile);
        api.setCorsProfiles(corsProfiles);

        Map inboundProfiles = new HashMap<>();
        InboundProfile profile = new InboundProfile();
        profile.setCorsProfile("Custom CORS");
        profile.setSecurityProfile(DEFAULT);
        profile.setMonitorAPI(true);
        profile.setMonitorSubject("authentication.subject.id");
        profile.setQueryStringPassThrough(false);
        inboundProfiles.put(DEFAULT, profile);
        api.setInboundProfiles(inboundProfiles);
        String frontendAuthType = parameters.getFrontendAuthType();
        // If frontendAuthType is null, use authentication from openapi spec. If none found, set it as pass through
        Map securityProfiles = addInboundSecurityToAPI(frontendAuthType);
        String backendAuthType = parameters.getBackendAuthType();
        addOutboundSecurityToAPI(api, backendAuthType);
        String apiSpecLocation;
        if (uri.startsWith("https")) {
            apiSpecLocation = downloadCertificatesAndContent(api, parameters.getConfig(), uri);
        } else if (uri.startsWith("http")) {
            apiSpecLocation = downloadContent(parameters.getConfig(), uri);
        } else {
            apiSpecLocation = parameters.getApiDefinition();
        }

        return new APIConfig(api, apiSpecLocation, securityProfiles);
    }

    public void addTags(API api, OpenAPI openAPI){
        List tags = openAPI.getTags();
        if(tags != null) {
            TagMap apiManagerTags = new TagMap();
            for (Tag tag : tags) {
                String[] value = new String[1];
                value[0] = tag.getName();
                apiManagerTags.put(tag.getName(), value);
            }
            api.setTags(apiManagerTags);
        }
    }

    public AuthType matchAuthType(String backendAuthType) {
        AuthType authType = null;
        try {
            authType = AuthType.valueOf(backendAuthType);
        } catch (IllegalArgumentException e) {
            LOG.error("Invalid backend auth type", e);
        }
        if (authType == null) {
            for (AuthType authTypeEnum : AuthType.values()) {
                String name = authTypeEnum.name();
                String[] alternativeNames = authTypeEnum.getAlternativeNames();
                if (name.equals(backendAuthType)) {
                    authType = authTypeEnum;
                    break;
                }
                for (String alternativeName : alternativeNames) {
                    if (alternativeName.equals(backendAuthType)) {
                        authType = authTypeEnum;
                        break;
                    }
                }
            }
        }
        return authType;
    }

    private void addOutboundSecurityToAPI(API api, String backendAuthType) throws AppException {
        AuthType authType = matchAuthType(backendAuthType);
        if (authType == null) {
            throw new AppException("backendAuthType : " + backendAuthType + "  is invalid", ErrorCode.INVALID_PARAMETER);
        }
        List authnProfiles = new ArrayList<>();
        AuthenticationProfile authNProfile = new AuthenticationProfile();
        authNProfile.setName(DEFAULT);
        authNProfile.setType(authType);
        authNProfile.setIsDefault(true);
        Map parameters = new LinkedHashMap<>();
        if (authType.equals(AuthType.apiKey)) {
            parameters.put("apiKey", "4249823490238490");
            parameters.put("apiKeyField", "KeyId");
            parameters.put("httpLocation", "QUERYSTRING_PARAMETER");
        } else if (authType.equals(AuthType.http_basic) || authType.equals(AuthType.http_digest)) {
            parameters.put("username", "user1");
            parameters.put("password", "password1");
        } else if (authType.equals(AuthType.oauth)) {
            parameters.put("providerProfile", "");
            parameters.put("ownerId", "${authentication.subject.id}");
        } else if (authType.equals(AuthType.ssl)) {
            parameters.put("source", "file");
            parameters.put("certFile", "../certificates/clientcert.pfx");
            parameters.put("password", Utils.getEncryptedPassword());
            parameters.put("trustAll", true);
        }
        authNProfile.setParameters(parameters);
        authnProfiles.add(authNProfile);
        api.setAuthenticationProfiles(authnProfiles);

    }

    public DeviceType matchDeviceType(String frontendAuthType) {
        DeviceType deviceType = null;
        try {
            deviceType = DeviceType.valueOf(frontendAuthType);
        } catch (IllegalArgumentException e) {
            LOG.debug("Invalid Frontend AuthType : {} going to try with alternate names", frontendAuthType);
        }

        if (deviceType == null) {
            for (DeviceType deviceTypeEnum : DeviceType.values()) {
                String name = deviceTypeEnum.name();
                String[] alternativeNames = deviceTypeEnum.getAlternativeNames();
                if (name.equals(frontendAuthType)) {
                    deviceType = deviceTypeEnum;
                    break;
                }
                for (String alternativeName : alternativeNames) {
                    if (alternativeName.equals(frontendAuthType)) {
                        deviceType = deviceTypeEnum;
                        break;
                    }
                }
            }
        }
        return deviceType;
    }

    private Map addInboundSecurityToAPI(String frontendAuthType) throws AppException {
        DeviceType deviceType = matchDeviceType(frontendAuthType);
        LOG.info("Frontend Authentication type : {}", frontendAuthType);
        if (deviceType == null) {
            throw new AppException("frontendAuthType : " + frontendAuthType + "  is invalid", ErrorCode.INVALID_PARAMETER);
        }
        APISecurity apiSecurity = new APISecurity();
        apiSecurity.setType(deviceType.toString());
        apiSecurity.setName(deviceType.getName());
        Map properties = new HashMap<>();
        if (deviceType.equals(DeviceType.apiKey)) {
            properties.put("apiKeyFieldName", "KeyId");
            properties.put("takeFrom", "HEADER");
            properties.put("removeCredentialsOnSuccess", "true");
        } else if (deviceType.equals(DeviceType.oauth)) {
            properties.put("tokenStore", "OAuth Access Token Store");
            properties.put("scopes", "resource.WRITE, resource.READ");
            setupOauthProperties(properties);
        } else if (deviceType.equals(DeviceType.oauthExternal)) {
            properties.put("tokenStore", "Tokeninfo policy 1");
            properties.put("useClientRegistry", true);
            properties.put("subjectSelector", "${oauth.token.client_id}");
            setupOauthProperties(properties);
        } else if (deviceType.equals(DeviceType.authPolicy)) {
            properties.put("authenticationPolicy", "Custom authentication policy");
            properties.put("useClientRegistry", true);
            properties.put("subjectSelector", "authentication.subject.id");
            properties.put("descriptionType", "original");
            properties.put("descriptionUrl", "");
            properties.put("descriptionMarkdown", "");
            properties.put("description", "");
        }
        apiSecurity.setProperties(properties);
        Map securityProfile = new LinkedHashMap<>();
        securityProfile.put("name", DEFAULT);
        securityProfile.put("isDefault", true);
        List apiSecurities = new ArrayList<>();
        apiSecurities.add(apiSecurity);
        securityProfile.put("devices", apiSecurities);
        return securityProfile;
    }

    private void setupOauthProperties(Map properties) {
        properties.put("accessTokenLocation", "HEADER");
        properties.put("authorizationHeaderPrefix", "Bearer");
        properties.put("accessTokenLocationQueryString", "");
        properties.put("scopesMustMatch", "Any");
        properties.put("scopes", "resource.WRITE, resource.READ");
        properties.put("removeCredentialsOnSuccess", true);
        properties.put("implicitGrantEnabled", true);
        properties.put("implicitGrantLoginEndpointUrl", "https://localhost:8089/api/oauth/authorize");
        properties.put("implicitGrantLoginTokenName", "access_token");
        properties.put("authCodeGrantTypeEnabled", true);
        properties.put("authCodeGrantTypeRequestEndpointUrl", "https://localhost:8089/api/oauth/authorize");
        properties.put("authCodeGrantTypeRequestClientIdName", "client_id");
        properties.put("authCodeGrantTypeRequestSecretName", "client_secret");
        properties.put("authCodeGrantTypeTokenEndpointUrl", "https://localhost:8089/api/oauth/token");
        properties.put("authCodeGrantTypeTokenEndpointTokenName", "access_code");
    }

    public String writeAPISpecification(String url, String configPath, InputStream inputStream) throws IOException {
        String filename;
        try {
            filename = new File(new URL(url).getPath()).getName();
            String content = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
            File file = new File(configPath);
            String parent = file.getParent();

            if (parent != null) {
                filename = file.toPath().getParent().toString() + File.separator + filename;
            }
            LOG.info("Writing API specification to : {}", filename);
            try (FileWriter fileWriter = new FileWriter(filename)) {
                fileWriter.write(content);
                fileWriter.flush();
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return filename;
    }

    public String downloadContent(String configPath, String url) throws IOException {
        URL httpURL = new URL(url);
        HttpURLConnection httpURLConnection = (HttpURLConnection) httpURL.openConnection();
        int responseCode = httpURLConnection.getResponseCode();
        String filePath = null;
        LOG.debug("Response Code : {}", responseCode);
        if (responseCode == HttpURLConnection.HTTP_OK) {
            filePath = writeAPISpecification(url, configPath, httpURLConnection.getInputStream());
        }
        return filePath;
    }


    public String downloadCertificatesAndContent(API api, String configPath, String url) throws IOException, CertificateEncodingException, NoSuchAlgorithmException, KeyManagementException {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }

            public void checkClientTrusted(X509Certificate[] certs, String authType) {//NOSONAR
            }

            public void checkServerTrusted(X509Certificate[] certs, String authType) {//NOSONAR
            }
        }};

        File file = new File(configPath);
        String parent = file.getParent();
        Base64.Encoder encoder = Base64.getMimeEncoder(64, System.lineSeparator().getBytes());
        URL httpURL = new URL(url);
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection httpsURLConnection = (HttpsURLConnection) httpURL.openConnection();
        httpsURLConnection.connect();
        Certificate[] certificates = httpsURLConnection.getServerCertificates();
        List caCerts = new ArrayList<>();
        for (Certificate certificate : certificates) {
            if (certificate instanceof X509Certificate) {
                X509Certificate publicCert = (X509Certificate) certificate;
                int basicConstraints = publicCert.getBasicConstraints();
                if (basicConstraints == -1 && (caCerts.size() > 1)) { // ignore for self signed certs
                    continue;
                }
                CaCert caCert = new CaCert();
                String encodedCertText = new String(encoder.encode(publicCert.getEncoded()));
                byte[] certContent = ("-----BEGIN CERTIFICATE-----\n" + encodedCertText + "\n-----END CERTIFICATE-----").getBytes();
                String filename = createCertFileName(publicCert);
                if (parent != null) {
                    filename = file.toPath().getParent().toString() + File.separator + filename;
                }
                try (FileOutputStream fileOutputStream = new FileOutputStream(filename)) {//NOSONAR
                    fileOutputStream.write(certContent);
                } catch (IOException e) {
                    throw new AppException("Can't write file", ErrorCode.UNXPECTED_ERROR, e);
                }
                caCert.setCertFile(filename);
                caCert.setInbound("false");
                caCert.setOutbound("true");
                caCerts.add(caCert);
            }
        }
        int responseCode = httpsURLConnection.getResponseCode();
        String filePath = null;
        LOG.debug("Response Code : {}", responseCode);
        if (responseCode == HttpURLConnection.HTTP_OK) {
            filePath = writeAPISpecification(url, configPath, httpsURLConnection.getInputStream());
        }
        api.setCaCerts(caCerts);
        return filePath;
    }

    public String createCertFileName(X509Certificate certificate) {
        String filename = null;
        String certAlias = certificate.getSubjectX500Principal().getName();
        String[] nameParts = certAlias.split(",");
        for (String namePart : nameParts) {
            if (namePart.trim().startsWith("CN=")) {
                filename = namePart.trim().substring(3);
                break;
            }
        }
        if (filename == null) {
            LOG.warn("No CN");
            filename = "UnknownCertificate_" + UUID.randomUUID();
            LOG.warn("Created a random filename: {}", filename);
        } else {
            filename = filename.replace(" ", "");
            filename = filename.replace("*", "");
            if (filename.startsWith(".")) filename = filename.replaceFirst("\\.", "");
        }
        return filename + ".crt";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy