Browse Source

improved fix for macro execution sequence

Jason Rivard 8 years ago
parent
commit
4e80dc2641

+ 8 - 1
src/main/java/password/pwm/util/macro/InternalMacros.java

@@ -107,7 +107,14 @@ public abstract class InternalMacros {
 
     public static class EncodingMacro extends AbstractMacro {
         private static final Pattern PATTERN = Pattern.compile("@Encode:[^:]+:\\[\\[.*\\]\\]@");
-        // @Encode:ENCODE_TYPE:value@
+        // @Encode:ENCODE_TYPE:[[value]]@
+
+
+        @Override
+        public Sequence getSequence()
+        {
+            return Sequence.post;
+        }
 
         private enum EncodeType {
             urlPath,

+ 10 - 0
src/main/java/password/pwm/util/macro/MacroImplementation.java

@@ -35,6 +35,11 @@ public interface MacroImplementation {
         User,
     }
 
+    enum Sequence {
+        normal,
+        post,
+    }
+
     Pattern getRegExPattern();
 
     String replaceValue( String matchValue,  MacroRequestInfo macroRequestInfo)
@@ -50,6 +55,11 @@ public interface MacroImplementation {
 
     MacroDefinitionFlag[] flags();
 
+    default Sequence getSequence()
+    {
+        return Sequence.normal;
+    }
+
     enum MacroDefinitionFlag {
         SensitiveValue,
         OnlyDebugLogging,

+ 27 - 21
src/main/java/password/pwm/util/macro/MacroMachine.java

@@ -165,20 +165,24 @@ public class MacroMachine {
         String workingString = input;
         final String previousString = workingString;
 
-        for (final Pattern pattern : macroImplementations.keySet()) {
-            final MacroImplementation pwmMacro = macroImplementations.get(pattern);
-            boolean matched = true;
-            while (matched) {
-                final Matcher matcher = pattern.matcher(workingString);
-                if (matcher.find()) {
-                    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;
+        for (final MacroImplementation.Sequence sequence : MacroImplementation.Sequence.values()) {
+            for (final Pattern pattern : macroImplementations.keySet()) {
+                final MacroImplementation pwmMacro = macroImplementations.get(pattern);
+                if (pwmMacro.getSequence() == sequence) {
+                    boolean matched = true;
+                    while (matched) {
+                        final Matcher matcher = pattern.matcher(workingString);
+                        if (matcher.find()) {
+                            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 {
+                            matched = false;
+                        }
                     }
-                } else {
-                    matched = false;
                 }
             }
         }
@@ -259,14 +263,6 @@ public class MacroMachine {
         String replace( String matchedMacro,  String newValue);
     }
 
-    /*
-    public static class URLEncoderReplacer implements StringReplacer {
-        public String replace(final String matchedMacro, final String newValue) {
-            return StringUtil.urlEncode(newValue); // make sure replacement values are properly encoded
-        }
-    }
-    */
-
     public static MacroMachine forUser(
             final PwmRequest pwmRequest,
             final UserIdentity userIdentity
@@ -276,6 +272,16 @@ public class MacroMachine {
         return forUser(pwmRequest.getPwmApplication(), pwmRequest.getLocale(), pwmRequest.getSessionLabel(),userIdentity);
     }
 
+    public static MacroMachine forUser(
+            final PwmApplication pwmApplication,
+            final SessionLabel sessionLabel,
+            final UserInfo userInfo,
+            final LoginInfoBean loginInfoBean
+
+    ) {
+        return new MacroMachine(pwmApplication, sessionLabel, userInfo, loginInfoBean);
+    }
+
     public static MacroMachine forUser(
             final PwmApplication pwmApplication,
             final Locale userLocale,

+ 108 - 0
src/test/java/password/pwm/util/macro/MacroTest.java

@@ -0,0 +1,108 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2017 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.util.macro;
+
+import org.junit.Assert;
+import org.junit.Test;
+import password.pwm.PwmApplication;
+import password.pwm.PwmApplicationMode;
+import password.pwm.PwmConstants;
+import password.pwm.bean.LoginInfoBean;
+import password.pwm.bean.UserIdentity;
+import password.pwm.config.Configuration;
+import password.pwm.config.stored.StoredConfigurationImpl;
+import password.pwm.ldap.UserInfo;
+
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class MacroTest {
+
+    @Test
+    public void testStaticMacros() throws Exception
+    {
+        final MacroMachine macroMachine = MacroMachine.forStatic();
+
+        { // app name
+            final String goal = "test " + PwmConstants.PWM_APP_NAME + " test";
+            final String expanded = macroMachine.expandMacros("test @PwmAppName@ test");
+            Assert.assertEquals(goal,expanded);
+        }
+
+        { // urlEncoding macro
+            final String goal = "https%3A%2F%2Fwww.example.com";
+            final String expanded = macroMachine.expandMacros("@Encode:urlPath:[[https://www.example.com]]@");
+            Assert.assertEquals(goal,expanded);
+        }
+
+        { // base64 macro
+            final String goal = "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20=";
+            final String expanded = macroMachine.expandMacros("@Encode:base64:[[https://www.example.com]]@");
+            Assert.assertEquals(goal,expanded);
+        }
+    }
+
+    @Test
+    public void testUserMacros() throws Exception
+    {
+
+        final String userDN = "cn=test1,ou=test,o=org";
+
+        final MacroMachine macroMachine;
+        {
+            final PwmApplication pwmApplication = mock(PwmApplication.class);
+            when(pwmApplication.getApplicationMode()).thenReturn(PwmApplicationMode.RUNNING);
+            when(pwmApplication.getConfig()).thenReturn(new Configuration(StoredConfigurationImpl.newStoredConfiguration()));
+
+            final UserInfo userInfo = mock(UserInfo.class);
+            final UserIdentity userIdentity = new UserIdentity(userDN, "profile");
+            when(userInfo.getUserIdentity()).thenReturn(userIdentity);
+            when(userInfo.readStringAttribute("givenName")).thenReturn("Jason");
+
+            final LoginInfoBean loginInfoBean = mock(LoginInfoBean.class);
+            when(loginInfoBean.isAuthenticated()).thenReturn(true);
+            when(loginInfoBean.getUserIdentity()).thenReturn(userIdentity);
+
+            macroMachine = MacroMachine.forUser(pwmApplication, null, userInfo, loginInfoBean);
+        }
+
+        { // userDN macro
+            final String goal = userDN;
+            final String expanded = macroMachine.expandMacros("@LDAP:dn@");
+            Assert.assertEquals(goal,expanded);
+        }
+
+        { // userDN + urlEncoding macro
+            final String goal = "test cn%3Dtest1%2Cou%3Dtest%2Co%3Dorg";
+            final String expanded = macroMachine.expandMacros("test @Encode:urlPath:[[@LDAP:dn@]]@");
+            Assert.assertEquals(goal,expanded);
+        }
+
+        { // user attribute macro
+            final String goal = "test Jason test";
+            final String expanded = macroMachine.expandMacros("test @LDAP:givenName@ test");
+            Assert.assertEquals(goal,expanded);
+        }
+    }
+}