afv-library/samples/webapp-template-app-react-sample-b2x-experimental/force-app/main/default/classes/WebAppAuthUtils.cls

69 lines
2.7 KiB
OpenEdge ABL

/**
* Utility class for Web Application authentication REST endpoints.
*/
public without sharing class WebAppAuthUtils {
/**
* Exception for authentication errors with HTTP status code support.
*/
public class AuthException extends Exception {
public Integer statusCode { get; private set; } // HTTP status code (e.g. 400, 500)
public List<String> messages { get; private set; } // List of error messages
public AuthException(Integer statusCode, String message) {
this.statusCode = statusCode;
this.messages = new List<String>{ message };
}
public AuthException(Integer statusCode, List<String> messages) {
this.statusCode = statusCode;
this.messages = new List<String>(messages);
}
}
/**
* Validates and sanitizes redirect URL to prevent open redirect vulnerabilities.
* @param url The URL to validate.
* @param defaultUrl Fallback URL if validation fails.
* @return Sanitized URL or defaultUrl if invalid.
*/
public static String getSanitizedStartUrl(String url, String defaultUrl) {
if (String.isBlank(url) || url.equals('/')) { return defaultUrl; }
String decoded; // Decode URL to catch encoded bypasses (%2f%2f -> //)
try {
decoded = EncodingUtil.urlDecode(url, 'UTF-8');
} catch (Exception e) {
return defaultUrl;
}
// Must start with / but not // (protocol-relative)
if (!decoded.startsWith('/') || decoded.startsWith('//')) { return defaultUrl; }
// Reject backslashes (some browsers treat \ as /)
if (decoded.contains('\\')) { return defaultUrl; }
// Reject @ which can indicate user info in URL (//user@evil.com)
if (decoded.contains('@')) { return defaultUrl; }
// Reject : which could indicate protocol or port manipulation
if (decoded.contains(':')) { return defaultUrl; }
// Reject control characters (ASCII < 32) and DEL (127)
for (Integer i = 0; i < decoded.length(); i++) {
Integer charCode = decoded.charAt(i);
if (charCode < 32 || charCode == 127) { return defaultUrl; }
}
return defaultUrl + url;
}
/**
* Logs an error message and stack trace to the system debug log.
* It is only captured if a Trace Flag is active for the user.
*
* @param ex The exception to log.
* @param level The logging level to use.
*/
public static void debugLog(Exception ex, LoggingLevel level) {
System.debug(level, 'Message: ' + ex.getMessage());
System.debug(level, 'Stack Trace: ' + ex.getStackTraceString());
}
}