57 lines
2.9 KiB
OpenEdge ABL
57 lines
2.9 KiB
OpenEdge ABL
/**
|
|
* ─────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
* PKCE (RFC 7636) helper for Connected Apps that have "Require Proof Key for Code Exchange" enabled.
|
|
* Generates the code_verifier / code_challenge pair, and packs/unpacks the verifier inside the
|
|
* OAuth `state` parameter so it survives the round-trip through the browser and back to Apex
|
|
* (works across orgs for the publisher-Site flow, and across browser tabs for the LWC flow).
|
|
* ──────────────────────────────────────────────────────────────────────────────────────────────────
|
|
*/
|
|
global with sharing class PkceUtil {
|
|
|
|
private static final String STATE_DELIMITER = '__pkce__';
|
|
|
|
global static String generateCodeVerifier() {
|
|
Blob random = Crypto.generateAesKey(256);
|
|
return base64UrlEncode(random);
|
|
}
|
|
|
|
global static String generateCodeChallenge(String codeVerifier) {
|
|
if (String.isBlank(codeVerifier)) return '';
|
|
Blob hash = Crypto.generateDigest('SHA-256', Blob.valueOf(codeVerifier));
|
|
return base64UrlEncode(hash);
|
|
}
|
|
|
|
global static String embedVerifierInState(String existingState, String verifier) {
|
|
String safeState = existingState == null ? '' : existingState;
|
|
return safeState + STATE_DELIMITER + (verifier == null ? '' : verifier);
|
|
}
|
|
|
|
global static String extractVerifier(String stateParam) {
|
|
if (String.isBlank(stateParam) || !stateParam.contains(STATE_DELIMITER)) return '';
|
|
Integer i = stateParam.indexOf(STATE_DELIMITER);
|
|
return stateParam.substring(i + STATE_DELIMITER.length());
|
|
}
|
|
|
|
global static String extractOriginalState(String stateParam) {
|
|
if (String.isBlank(stateParam) || !stateParam.contains(STATE_DELIMITER)) return stateParam;
|
|
return stateParam.substring(0, stateParam.indexOf(STATE_DELIMITER));
|
|
}
|
|
|
|
@AuraEnabled
|
|
global static Map<String, String> issuePkceForState(String existingState) {
|
|
String verifier = generateCodeVerifier();
|
|
String challenge = generateCodeChallenge(verifier);
|
|
String state = embedVerifierInState(existingState, verifier);
|
|
Map<String, String> result = new Map<String, String>();
|
|
result.put('codeChallenge', challenge);
|
|
result.put('state', state);
|
|
return result;
|
|
}
|
|
|
|
private static String base64UrlEncode(Blob input) {
|
|
return EncodingUtil.base64Encode(input)
|
|
.replace('+', '-')
|
|
.replace('/', '_')
|
|
.replace('=', '');
|
|
}
|
|
} |