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

one.credify.sdk.impl.OidcServiceImpl Maven / Gradle / Ivy

package one.credify.sdk.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import one.credify.crypto.Encryption;
import one.credify.crypto.Jwt;
import one.credify.sdk.CredifyConfig;
import one.credify.sdk.OidcService;
import one.credify.sdk.dto.OidcOptions;
import one.credify.sdk.dto.OidcResponse;
import one.credify.sdk.dto.UserInfoRes;
import one.credify.sdk.mapper.UserInfoResMapper;
import one.credify.sdk.model.UserOidcInfo;
import one.credify.sdk.restapi.OidcCoreRest;
import one.credify.sdk.utils.Constants;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.*;

public class OidcServiceImpl implements OidcService {
    private static final String COMMITMENT_KEY = "commitment";

    private final CredifyConfig config;
    private final OidcCoreRest oidcCoreClient;

    public OidcServiceImpl(CredifyConfig config, OidcCoreRest oidcCoreClient) {
        this.config = config;
        this.oidcCoreClient = oidcCoreClient;
    }

    public OidcResponse initiateOidc(String consumerId, String redirectUrl, String[] scopes, OidcOptions options) throws JsonProcessingException {
        String state = UUID.randomUUID().toString().replace("-", "");
        String nonce = UUID.randomUUID().toString().replace("-", "");
        List finalScopes = new ArrayList<>(Arrays.asList(scopes));

        if (StringUtils.isNotEmpty(options.getOfferCode())) {
            String offerScope = "offer:" + options.getOfferCode();
            if (StringUtils.isNotEmpty(options.getPackageCode())) {
                offerScope = offerScope + ":" + options.getPackageCode();
            }
            finalScopes.add(offerScope);
        }

        if (StringUtils.isNotEmpty(options.getProductCode())) {
            String scope = "product:" + options.getProductCode();
            if (StringUtils.isNotEmpty(options.getPackageCode())) {
                scope = scope + ":" + options.getPackageCode();
            }
            finalScopes.add(scope);
        }

        if (StringUtils.isNotEmpty(options.getDopCode())) {
            finalScopes.add("dop:" + options.getDopCode());
        }

        if (StringUtils.isNotEmpty(options.getOrderId())) {
            finalScopes.add("bnpl_order:" + options.getOrderId());
        }

        String formattedScopes = StringUtils.join(finalScopes.toArray(), " ");

        String requestToken = this.config.getSigning().generateRequestToken(consumerId, "", finalScopes, options.getOfferCode(), options.getPackageCode(), options.getDopCode());

        Map params = new HashMap<>();
        params.put("client_id", consumerId);
        params.put("redirect_uri", redirectUrl);
        params.put("scope", formattedScopes);
        params.put("response_type", !options.getResponseType().equals("") ? options.getResponseType() : "code");
        params.put("response_mode", !options.getResponseMode().equals("") ? options.getResponseMode() : "query");
        params.put("state", !options.getState().equals("") ? options.getState() : state);
        params.put("nonce", nonce);
        params.put("request_token", requestToken);
        if (StringUtils.isNotEmpty(options.getPhoneNumber())) {
            params.put("phone_number", options.getPhoneNumber());
        }
        if (StringUtils.isNotEmpty(options.getCountryCode())) {
            params.put("country_code", options.getCountryCode());
        }
        if (StringUtils.isNotEmpty(options.getEntityId())) {
            params.put("entity_id", options.getEntityId());
        }
        if (StringUtils.isNotEmpty(options.getLocalId())) {
            params.put("local_id", options.getLocalId());
        }
        String oidcCoreUrl = this.config.getOidcCoreUrl();
        String q = params.entrySet().stream()
                .map(p -> {
                    if (p == null) {
                        return null;
                    }
                    try {
                        return URLEncoder.encode(p.getKey(), "UTF-8") + "=" + URLEncoder.encode((String) p.getValue(), "UTF-8");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return null;
                })
                .reduce((p1, p2) -> p1 + "&" + p2)
                .orElse("")
                .replace("+", "%20");

        String url = oidcCoreUrl + "/oauth2/auth?" + q;
        return new OidcResponse(url, null, state, nonce);
    }

    public UserOidcInfo getUserInfo(String accessToken, String privateKey) throws Exception {
        Encryption encryption;
        if (StringUtils.isNotEmpty(privateKey)) {
            encryption = new Encryption();
            encryption.importPrivateKey(privateKey);
        } else {
            encryption = config.getEncryption();
        }
        String authorization = "Bearer " + accessToken;
        UserInfoRes userInfoRes = this.oidcCoreClient.getUserInfo(authorization).execute().body();
        if (userInfoRes == null) {
            return null;
        }
        Map customClaims = new HashMap<>();
        Map customClaimCommitments = new HashMap<>();
        UserOidcInfo.Commitment commitment = UserOidcInfo.Commitment.builder()
                .customClaimCommitments(customClaimCommitments)
                .build();
        UserInfoRes.UserInfo userInfo = new UserInfoRes.UserInfo();
        // parsing claim source jwe value
        for (String scopeName : userInfoRes.getClaimSources().keySet()) {
            UserInfoRes.ClaimSourceValue value = userInfoRes.getClaimSources().get(scopeName);
            if (StringUtils.isEmpty(value.getJwt())) {
                continue;
            }
            // parse jwe value
            Jwt jwt = Jwt.parseJwe(encryption, value.getJwt());
            // checking custom scope name
            if (scopeName.split(Constants.CUSTOM_SCOPE_NAME_SPLIT).length > 1) {
                for (String claimName : jwt.getPayload().keySet()) {
                    String[] claimParts = claimName.split(Constants.CUSTOM_SCOPE_NAME_SPLIT);
                    if (COMMITMENT_KEY.equals(claimParts[claimParts.length - 1])) {
                        customClaimCommitments.put(claimName, String.valueOf(jwt.getPayload().get(claimName)));
                    } else {
                        customClaims.put(claimName, String.valueOf(jwt.getPayload().get(claimName)));
                    }
                }
            }

            // map json value and set user info by each specific scope name
            switch (scopeName) {
                case Constants.STANDARD_SCOPE_NAME_OPENID:
                    userInfo.setOpenid(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.OpenidDto.class));
                    break;
                case Constants.STANDARD_SCOPE_NAME_PROFILE:
                    userInfo.setProfile(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.Profile.class));
                    commitment.setProfileCommitment(userInfo.getProfile().getProfileCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_ADVANCED_PROFILE:
                    userInfo.setAdvanceProfile(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.AdvanceProfile.class));
                    commitment.setAdvancedProfileCommitment(userInfo.getAdvanceProfile().getAdvancedProfileCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_PHONE:
                    userInfo.setPhone(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.Phone.class));
                    commitment.setPhoneCommitment(userInfo.getPhone().getPhoneCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_EMAIL:
                    userInfo.setEmail(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.Email.class));
                    commitment.setEmailCommitment(userInfo.getEmail().getEmailCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_ADDRESS:
                    UserInfoRes.AddressDto addressDto = Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.AddressDto.class);
                    userInfo.setAddress(addressDto.getAddress());
                    commitment.setAddressCommitment(addressDto.getAddressCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_PERMANENT_ADDRESS:
                    UserInfoRes.PermanentAddressDto permanentAddressDto = Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.PermanentAddressDto.class);
                    userInfo.setPermanentAddress(permanentAddressDto.getPermanentAddress());
                    commitment.setPermanentAddressCommitment(permanentAddressDto.getPermanentAddressCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_EMPLOYMENT:
                    UserInfoRes.EmploymentDto employmentDto = Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.EmploymentDto.class);
                    userInfo.setEmployment(employmentDto.getEmployment());
                    commitment.setEmploymentCommitment(employmentDto.getEmploymentCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_INCOME:
                    userInfo.setIncome(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.Income.class));
                    commitment.setIncomeCommitment(userInfo.getIncome().getIncomeCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_BANK_ACCOUNT:
                    UserInfoRes.BankAccountDto bankAccountDto = Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.BankAccountDto.class);
                    userInfo.setBankAccount(bankAccountDto.getBankAccount());
                    commitment.setBankAccountCommitment(bankAccountDto.getBankAccountCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_PRIMARY_REFERENCE_PERSON:
                    UserInfoRes.PrimaryReferencePersonDto primaryReferencePersonDto = Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.PrimaryReferencePersonDto.class);
                    userInfo.setPrimaryReferencePerson(primaryReferencePersonDto.getPrimaryReferencePerson());
                    commitment.setPrimaryReferencePersonCommitment(primaryReferencePersonDto.getPrimaryReferencePersonCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_SECONDARY_REFERENCE_PERSON:
                    UserInfoRes.SecondaryReferencePersonDto secondaryReferencePersonDto = Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.SecondaryReferencePersonDto.class);
                    userInfo.setSecondaryReferencePerson(secondaryReferencePersonDto.getSecondaryReferencePerson());
                    commitment.setSecondaryReferencePersonCommitment(secondaryReferencePersonDto.getSecondaryReferencePersonCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_SPOUSE:
                    UserInfoRes.SpouseDto spouseDto = Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.SpouseDto.class);
                    userInfo.setSpouse(spouseDto.getSpouse());
                    commitment.setSpouseCommitment(spouseDto.getSpouseCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_EKYC:
                    userInfo.setEkyc(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.Ekyc.class));
                    commitment.setEkycCommitment(userInfo.getEkyc().getEkycCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_IDCARD:
                    userInfo.setIdcard(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.Idcard.class));
                    commitment.setIdcardCommitment(userInfo.getIdcard().getIdcardCommitment());
                    break;
                case Constants.STANDARD_SCOPE_NAME_DRIVING_PERMIT:
                    userInfo.setDrivingPermit(Constants.MAPPER.readValue(jwt.getRawPayload(), UserInfoRes.DrivingPermit.class));
                    commitment.setDrivingPermitCommitment(userInfo.getDrivingPermit().getDrivingPermitCommitment());
                    break;
            }
        }
        // mapping decrypted user response to our standard user oidc info result
        UserOidcInfo result = UserInfoResMapper.INSTANCE.fromResponse(userInfo);
        result.setCredifyId(userInfoRes.getSub());
        result.setCustomClaims(customClaims);
        result.setCommitment(commitment);

        // update ekyc info
        if (userInfo.getIdcard() != null) {
            result.getIdcard().updateEkycInfo(userInfo.getIdcard());
            result.setIdcardOldNumber(userInfo.getIdcard().getIdcardOldNumber());
        }
        if (userInfo.getDrivingPermit() != null) {
            result.getDrivingPermit().updateEkycInfo(userInfo.getDrivingPermit());
        }
        if (userInfo.getEkyc() != null) {
            result.getEkyc().updateEkycInfo(userInfo.getEkyc());
        }
        return result;
    }

    @Override
    public Map generateAccessToken(String consumerId, String code, String redirectUri) throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
        String token = this.config.getSigning().generateJwt();
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("code", code)
                .addFormDataPart("grant_type", "authorization_code")
                .addFormDataPart("redirect_uri", redirectUri)
                .addFormDataPart("client_secret", token)
                .addFormDataPart("client_id", consumerId)
                .addFormDataPart("client_type", "entity").build();
        return this.oidcCoreClient.generateAccessToken(requestBody).execute().body();
    }

    private Object trimObject(Object obj) {
        if (obj instanceof String) {
            String objString = (String) obj;
            return objString.replaceAll("\"", "");
        }
        if (obj instanceof Map) {
            Map objMap = (Map) obj;
            Map result = new HashMap<>();
            objMap.forEach((key, value) -> {
                result.put(key, trimObject(value));
            });
            return result;
        }
        return obj;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy