|
@@ -23,14 +23,15 @@
|
|
package password.pwm.util.macro;
|
|
package password.pwm.util.macro;
|
|
|
|
|
|
import password.pwm.PwmApplication;
|
|
import password.pwm.PwmApplication;
|
|
|
|
+import password.pwm.PwmApplicationMode;
|
|
import password.pwm.PwmConstants;
|
|
import password.pwm.PwmConstants;
|
|
|
|
+import password.pwm.bean.LoginInfoBean;
|
|
import password.pwm.bean.SessionLabel;
|
|
import password.pwm.bean.SessionLabel;
|
|
import password.pwm.bean.UserIdentity;
|
|
import password.pwm.bean.UserIdentity;
|
|
import password.pwm.bean.UserInfoBean;
|
|
import password.pwm.bean.UserInfoBean;
|
|
import password.pwm.config.PwmSetting;
|
|
import password.pwm.config.PwmSetting;
|
|
import password.pwm.error.PwmUnrecoverableException;
|
|
import password.pwm.error.PwmUnrecoverableException;
|
|
import password.pwm.http.PwmRequest;
|
|
import password.pwm.http.PwmRequest;
|
|
-import password.pwm.bean.LoginInfoBean;
|
|
|
|
import password.pwm.ldap.LdapUserDataReader;
|
|
import password.pwm.ldap.LdapUserDataReader;
|
|
import password.pwm.ldap.UserDataReader;
|
|
import password.pwm.ldap.UserDataReader;
|
|
import password.pwm.ldap.UserStatusReader;
|
|
import password.pwm.ldap.UserStatusReader;
|
|
@@ -50,7 +51,8 @@ public class MacroMachine {
|
|
private final UserInfoBean userInfoBean;
|
|
private final UserInfoBean userInfoBean;
|
|
private final LoginInfoBean loginInfoBean;
|
|
private final LoginInfoBean loginInfoBean;
|
|
private final UserDataReader userDataReader;
|
|
private final UserDataReader userDataReader;
|
|
- private final Map<Pattern,MacroImplementation> macroImplementations;
|
|
|
|
|
|
+
|
|
|
|
+ private static final Map<MacroImplementation.Scope,Map<Pattern,MacroImplementation>> BUILTIN_MACROS = makeImplementations();
|
|
|
|
|
|
public MacroMachine(
|
|
public MacroMachine(
|
|
final PwmApplication pwmApplication,
|
|
final PwmApplication pwmApplication,
|
|
@@ -65,25 +67,33 @@ public class MacroMachine {
|
|
this.userInfoBean = userInfoBean;
|
|
this.userInfoBean = userInfoBean;
|
|
this.loginInfoBean = loginInfoBean;
|
|
this.loginInfoBean = loginInfoBean;
|
|
this.userDataReader = userDataReader;
|
|
this.userDataReader = userDataReader;
|
|
- this.macroImplementations = makeImplementations();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- private Map<Pattern,MacroImplementation> makeImplementations() {
|
|
|
|
- final Set<Class<? extends MacroImplementation>> implementations = new HashSet<>();
|
|
|
|
- implementations.addAll(StandardMacros.STANDARD_MACROS);
|
|
|
|
- implementations.addAll(InternalMacros.INTERNAL_MACROS);
|
|
|
|
- final LinkedHashMap<Pattern,MacroImplementation> map = new LinkedHashMap<>();
|
|
|
|
|
|
+ private static Map<MacroImplementation.Scope,Map<Pattern,MacroImplementation>> makeImplementations() {
|
|
|
|
+ final Map<Class<? extends MacroImplementation>, MacroImplementation.Scope> implementations = new LinkedHashMap<>();
|
|
|
|
+ implementations.putAll(StandardMacros.STANDARD_MACROS);
|
|
|
|
+ implementations.putAll(InternalMacros.INTERNAL_MACROS);
|
|
|
|
+ final LinkedHashMap<MacroImplementation.Scope,Map<Pattern,MacroImplementation>> map = new LinkedHashMap<>();
|
|
|
|
|
|
- for (Class macroClass : implementations) {
|
|
|
|
|
|
+ for (Class macroClass : implementations.keySet()) {
|
|
|
|
+ final MacroImplementation.Scope scope = implementations.get(macroClass);
|
|
try {
|
|
try {
|
|
final MacroImplementation macroImplementation = (MacroImplementation)macroClass.newInstance();
|
|
final MacroImplementation macroImplementation = (MacroImplementation)macroClass.newInstance();
|
|
final Pattern pattern = macroImplementation.getRegExPattern();
|
|
final Pattern pattern = macroImplementation.getRegExPattern();
|
|
- map.put(pattern,macroImplementation);
|
|
|
|
|
|
+ if (!map.containsKey(scope)) {
|
|
|
|
+ map.put(scope, new LinkedHashMap<Pattern, MacroImplementation>());
|
|
|
|
+ }
|
|
|
|
+ map.get(scope).put(pattern,macroImplementation);
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
- LOGGER.error(sessionLabel, "unable to load macro class " + macroClass.getName() + ", error: " + e.getMessage());
|
|
|
|
|
|
+ LOGGER.error("unable to load macro class " + macroClass.getName() + ", error: " + e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ return map;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Map<Pattern,MacroImplementation> makeExternalImplementations(PwmApplication pwmApplication) {
|
|
|
|
+ final LinkedHashMap<Pattern,MacroImplementation> map = new LinkedHashMap<>();
|
|
final List<String> externalMethods = pwmApplication == null
|
|
final List<String> externalMethods = pwmApplication == null
|
|
? Collections.<String>emptyList()
|
|
? Collections.<String>emptyList()
|
|
: pwmApplication.getConfig().readSettingAsStringArray(PwmSetting.EXTERNAL_MACROS_REST_URLS);
|
|
: pwmApplication.getConfig().readSettingAsStringArray(PwmSetting.EXTERNAL_MACROS_REST_URLS);
|
|
@@ -146,8 +156,16 @@ public class MacroMachine {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ final Map<Pattern,MacroImplementation> macroImplementations = new LinkedHashMap<>();
|
|
|
|
+ for (final MacroImplementation.Scope scope : effectiveScopes()) {
|
|
|
|
+ macroImplementations.putAll(BUILTIN_MACROS.get(scope));
|
|
|
|
+ }
|
|
|
|
+ if (effectiveScopes().contains(MacroImplementation.Scope.User)) {
|
|
|
|
+ macroImplementations.putAll(makeExternalImplementations(pwmApplication));
|
|
|
|
+ }
|
|
|
|
|
|
String workingString = input;
|
|
String workingString = input;
|
|
|
|
+ String previousString = workingString;
|
|
|
|
|
|
for (final Pattern pattern : macroImplementations.keySet()) {
|
|
for (final Pattern pattern : macroImplementations.keySet()) {
|
|
final MacroImplementation pwmMacro = macroImplementations.get(pattern);
|
|
final MacroImplementation pwmMacro = macroImplementations.get(pattern);
|
|
@@ -156,6 +174,11 @@ public class MacroMachine {
|
|
final Matcher matcher = pattern.matcher(workingString);
|
|
final Matcher matcher = pattern.matcher(workingString);
|
|
if (matcher.find()) {
|
|
if (matcher.find()) {
|
|
workingString = doReplace(workingString, pwmMacro, matcher, stringReplacer, macroRequestInfo);
|
|
workingString = doReplace(workingString, pwmMacro, matcher, stringReplacer, macroRequestInfo);
|
|
|
|
+ if (workingString.equals(previousString)) {
|
|
|
|
+ LOGGER.warn(sessionLabel, "macro replace was called but input string was not modified. "
|
|
|
|
+ + " macro=" + pwmMacro.getClass().getName() + ", pattern=" + pwmMacro.getRegExPattern().toString());
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
matched = false;
|
|
matched = false;
|
|
}
|
|
}
|
|
@@ -165,6 +188,21 @@ public class MacroMachine {
|
|
return workingString;
|
|
return workingString;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private Set<MacroImplementation.Scope> effectiveScopes() {
|
|
|
|
+ final Set<MacroImplementation.Scope> scopes = new HashSet<>();
|
|
|
|
+ scopes.add(MacroImplementation.Scope.Static);
|
|
|
|
+ if (this.pwmApplication != null
|
|
|
|
+ && (pwmApplication.getApplicationMode() == PwmApplicationMode.RUNNING || pwmApplication.getApplicationMode() == PwmApplicationMode.CONFIGURATION)
|
|
|
|
+ ) {
|
|
|
|
+ scopes.add(MacroImplementation.Scope.System);
|
|
|
|
+ if (this.userInfoBean != null && this.userDataReader != null) {
|
|
|
|
+ scopes.add(MacroImplementation.Scope.User);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return Collections.unmodifiableSet(scopes);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
private String doReplace(
|
|
private String doReplace(
|
|
final String input,
|
|
final String input,
|
|
final MacroImplementation macroImplementation,
|
|
final MacroImplementation macroImplementation,
|