0

enter image description here

Here is the class that am using ,based on the flow that I have ,the validation always fails and return false in the line boolean isValid = signature.verify(signatureBytes); LOG.info("Signature valid? {}", isValid); can i plase request you to validate and advie what is it that am doing wrong and i am trying to use only java libraries for validations or conversions. Am not sure if am using right libs / code to vlaidate the token.

package com.wwg.integrations.validator;
import de.hybris.platform.servicelayer.config.ConfigurationService;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import javax.net.ssl.SSLContext;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyFactory;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;

public class CaptureContextTokenValidator {
    private static final Logger LOG = LoggerFactory.getLogger(WWGCaptureContextTokenValidator.class);
    public static final String CYBERSOURCE_PUBLIC_KEY_URL = "cybersource.public.key.url";
    private ConfigurationService configurationService;

    public boolean validateCaptureContextToken(String captureContextToken) {
        if (captureContextToken == null || captureContextToken.isEmpty()) {
            LOG.error("Capture context token is null or empty");
            return false;
        }
        String kidId = extractKidFromJWTToken(captureContextToken);
        JSONObject jwkJson = fetchRSAKeyUsingKidId(kidId);
        try {
            PublicKey publicKey = extractPublicKeyFromJWK(jwkJson);
            LOG.info("Public Key: " + publicKey);
            return validateCaptureContextWithPublicKey(captureContextToken, publicKey);
        } catch (Exception e) {
            throw new RuntimeException("Error during validation", e);
        }
    }

    private JSONObject fetchRSAKeyUsingKidId(String kidId) {
        RestTemplate restTemplate = getRestTemplate();
        final String publicKeyURL = getConfigurationService().getConfiguration().getString(CYBERSOURCE_PUBLIC_KEY_URL) + kidId;
        LOG.info("Fetching public key using : " + publicKeyURL);

        try {
            URI uri = new URI(publicKeyURL);
            HttpEntity<String> requestEntity = new HttpEntity<>(null, null);
            ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.GET, requestEntity, String.class);
            String jsonResponse = result.getBody();
            LOG.info("Response from public key fetch: " + jsonResponse);
            return new JSONObject(jsonResponse);
        } catch (URISyntaxException e) {
            throw new RuntimeException("Invalid URI", e);
        } catch (Exception e) {
            throw new RuntimeException("Error parsing JSON response", e);
        }
    }

    private RestTemplate getRestTemplate() {
        try {
            SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                    .loadTrustMaterial(null, (X509Certificate[] chain, String authType) -> true)
                    .build();
            HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
            requestFactory.setHttpClient(HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext)).build());
            return new RestTemplate(requestFactory);
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            throw new RuntimeException("Error creating RestTemplate", e);
        }
    }

    public PublicKey extractPublicKeyFromJWK(JSONObject jwk) throws Exception {
        // Extract the modulus and exponent
        String n = jwk.getString("n");
        String e = jwk.getString("e");

        // Add padding to make Base64 decoding safe
        n = addBase64Padding(n);
        e = addBase64Padding(e);

        // Decode using URL-safe decoder
        byte[] modulusBytes = Base64.getUrlDecoder().decode(n);
        byte[] exponentBytes = Base64.getUrlDecoder().decode(e);

        // Convert to BigInteger
        BigInteger modulus = new BigInteger(1, modulusBytes);
        BigInteger exponent = new BigInteger(1, exponentBytes);

        // Create the public key spec
        RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
        KeyFactory factory = KeyFactory.getInstance("RSA");

        return factory.generatePublic(spec);
    }

    private String addBase64Padding(String base64) {
        int paddingLength = (4 - base64.length() % 4) % 4;
        return base64 + "=".repeat(paddingLength);
    }

    private boolean validateCaptureContextWithPublicKey(String captureContextToken, PublicKey publicKey) {
        try {
            // Split the JWT token into parts
            String[] parts = captureContextToken.split("\\.");
            if (parts.length != 3) {
                LOG.error("Invalid JWT token format: {}", captureContextToken);
                return false;
            }

            // Construct header and payload
            String headerAndPayload = parts[0] + "." + parts[1];
            byte[] signatureBytes = Base64.getUrlDecoder().decode(parts[2]);

            // Initialize the Signature instance
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initVerify(publicKey);

            // Update the Signature instance with header and payload
            signature.update(headerAndPayload.getBytes(StandardCharsets.US_ASCII));

            // Verify the signature
            boolean isValid = signature.verify(signatureBytes);
            LOG.info("Signature valid? {}", isValid);
            return isValid;
        } catch (Exception e) {
            LOG.error("Error validating JWT signature", e);
            return false;
        }
    }


    private String extractKidFromJWTToken(String jwt) {
        try {
            String[] parts = jwt.split("\\.");
            if (parts.length < 2) {
                throw new IllegalArgumentException("Invalid JWT token format");
            }
            String bodyData = new String(Base64.getUrlDecoder().decode(parts[1]));
            JSONObject jsonObject = new JSONObject(bodyData);
            return     jsonObject
                    .getJSONObject("flx")
                    .getJSONObject("jwk")
                    .optString("kid");
        } catch (Exception e) {
            throw new RuntimeException("Failed to extract kid from JWT token", e);
        }
    }

    public ConfigurationService getConfigurationService() {
        return configurationService;
    }
    public void setConfigurationService(ConfigurationService configurationService) {
        this.configurationService = configurationService;
    }

}

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.